https://www.acmicpc.net/problem/16499

 

16499번: 동일한 단어 그룹화하기

첫째 줄에 단어의 개수 N이 주어진다. (2 ≤ N ≤ 100) 둘째 줄부터 N개의 줄에 단어가 한 줄에 하나씩 주어진다. 단어는 알파벳 소문자로만 이루어져 있고, 길이는 10을 넘지 않는다.

www.acmicpc.net

문제

소문자로 이루어진 단어 N개가 주어졌을 때, 단어가 총 최소 몇 개의 그룹으로 이루어져 있는지 구하는 프로그램을 작성하시오.

그룹에 속한 단어는 모두 같은 알파벳으로 이루어져 있어야 하고, 개수도 같아야 한다. 즉, 단어를 구성하는 알파벳의 순서만 달라야 한다.

입력

첫째 줄에 단어의 개수 N이 주어진다. (2 ≤ N ≤ 100) 둘째 줄부터 N개의 줄에 단어가 한 줄에 하나씩 주어진다. 단어는 알파벳 소문자로만 이루어져 있고, 길이는 10을 넘지 않는다.

출력

첫째 줄에 그룹의 최소 개수를 출력한다.

예제 입력 1 복사

4
cat
dog
god
tca

예제 출력 1 복사

2

예제 입력 2 복사

2
a
a

예제 출력 2 복사

1

 

문제풀이(1)

1. 정해진 단어들을 오름차순으로 정렬한다.
2. set 객체를 활용하여 중복되는 단어들을 제거한다.
3. 중복이 제거된 set 객체의 size를 출력한다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const [N, ...arr] = require("fs").readFileSync(filePath).toString().trim().split("\n");

const setArr = new Set();

arr.forEach((el) => {
  setArr.add(el.split("").sort().join(""));
});

console.log(setArr.size);

https://www.acmicpc.net/problem/14594

 

14594번: 동방 프로젝트 (Small)

첫 번째 행동으로 1번과 2번 방이 합쳐져 (1, 2), (3), (4), (5) 상태가 된다. 이후 두 번째 행동으로 2, 3, 4번 방이 합쳐져 (1, 2, 3, 4), (5)의 상태가 된다. 따라서 남아있는 동방의 수는 2가 된다.

www.acmicpc.net

문제

동아리방이 가지고 싶었던 병찬이는 LINK 사업단에 문의하여 N개의 방 중의 하나를 얻을 기회를 얻었다. 일자로 되어있는 건물에 N개의 방은 일직선상에 존재하며, 각 방에는 번호가 매겨져 있다. 맨 왼쪽 방의 번호는 1번이며, 순서대로 증가하여 맨 오른쪽 방의 번호가 N번이다. 각 방 사이에는 방을 구분하는 벽이 존재한다.

물론 병찬이 외에도 많은 사람이 동아리방을 원한다. 다행히 방은 충분했기에 병찬이는 안심하고 있었지만…

그때였다.

빅-종빈빌런이 나타나 건물 벽을 허물기 시작한 것이다! 빅-종빈빌런은 다음과 같은 규칙으로 벽을 무너뜨린다.

  • x < y 를 만족하는 두 방에 대해서 x번 방부터 y번 방 사이에 있는 모든 벽을 허문다.
  • 두 방 사이의 벽이 허물어지면 두 방은 하나의 방으로 합쳐진다.
  • 이미 허물어진 벽이 존재한다면 무시하고 다음 벽을 허문다.
  • 빅-종빈빌런은 건물이 무너지는 걸 원치 않기 때문에, 1번 방의 왼쪽 벽과 N번 방의 오른쪽 벽(즉, 바깥과 연결된 벽)은 허물지 않는다.

동아리 방의 개수가 점점 줄어들자 병찬이는 초조해졌다. 이에 병찬이는 동아리방을 얻을 수 있는지에 대한 확률을 계산하기 위해 남는 동아리방의 수를 구하고 싶어 한다. 병찬이를 위해 빅-종빈빌런의 행동 횟수 M과 동방의 개수 N이 주어졌을 때, 남은 동아리방의 수를 구해주자.

입력

첫 번째 줄에는 동아리방의 개수를 나타내는 양의 정수 N(2 ≤ N ≤ 100) 이 주어진다. 두 번째 줄에는 빅-종빈빌런의 행동 횟수를 나타내는 음이 아닌 정수 M(0 ≤ M ≤ 100) 이 주어진다. 세 번째 줄부터 M개의 줄에 걸쳐 빅-종빈빌런의 행동이 양의 정수 x, y(1 ≤ x < y ≤ N) 로 주어진다. 여기서 행동이란 x번 방부터 y번 방 사이의 벽을 무너뜨리는 것을 의미한다.

빅-종빈빌런은 매우 허당이기 때문에 동일한 행동을 여러 번 할 수 있음에 유의하라.

출력

빅-종빈빌런의 모든 행동이 끝난 후 남아있는 동방의 개수를 한 줄에 출력한다.

예제 입력 1 복사

5
2
1 2
2 4

예제 출력 1 복사

2

예제 입력 2 복사

5
1
1 5

예제 출력 2 복사

1

 

문제풀이(1)

동아리방의 개수 = 5, 빅-종빈빌런의 행동횟수 = 2,
빅-종빈빌런의 행동 양의정수 x = 1, 2, y = 2, 4
true, true, true, true, true이고, x < y 일 때, 사이의 방을부순다.
2번의 행동 모두 위의 조건을 만족하기 때문에 사이의 벽을 부순다.
첫번째 행동: true, false, true, true, true
두번째 행동: true, false, false, false, true
벽이 사라진다는 것은 x < 부숴지는 방 <= y 이다.

1. N만큼의 배열의 공간에 true로 방을 만든다.
2. 시작방과 끝방-1만큼 반복문을 순회하며 false로 방을 제거한다.
3. 남아있는 방의 개수를 카운트한다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const input = require("fs").readFileSync(filePath).toString().trim().split("\n");

const N = Number(input.shift());
const M = Number(input.shift());

// true = 부숴지지 않은 벽, false = 부숴진 벽
const walls = Array.from({ length: N }).fill(true);

for (let i = 0; i < M; i++) {
  const [startRoom, endRoom] = input[i].split(" ").map(Number);

  for (let j = startRoom; j < endRoom; j++) {
    walls[j] = false;
  }
}

console.log(walls.filter((el) => el === true).length);

https://www.acmicpc.net/problem/15736

 

15736번: 청기 백기

예제 입력 1의 경우 1, 2, 3번 깃발이 존재하고, 3명의 선수가 참가한다. 첫 번째 선수는 1의 배수의 번호를 가진 깃발을 뒤집는다. 초기에 청색이였던 깃발은 첫 번째 선수에 의해 모두 백기로 된

www.acmicpc.net

문제

소프트웨어융합대학 학생회에서 주최한 소융체전에서 청기 백기 뒤집기 게임이 한창이다. 소프트웨어학부, ICT융합학부가 번갈아가면서 게임을 진행하는 중이다. 게임의 규칙은 간단하다. 게임을 진행할 차례인 학부에서 출전한 선수들 N명이 존재한다. 학생들의 앞 탁자에는 N개의 깃발이 청색이 위로 백색이 아래로 보이도록 놓여있다. 이때 출전한 선수 중 첫 번째 선수는 N개의 깃발 중 1의 배수에 해당하는 번호의 깃발을 뒤집어 놓는다. 다음 두 번째 선수는 N개의 깃발 중 2의 배수에 해당하는 번호의 깃발을 뒤집어 놓는다. i 번째 선수는 i의 배수에 해당하는 번호의 깃발을 뒤집고, N 번째 선수까지 진행하면 끝이 난다. 그렇다면 이 게임에서 N 명의 선수가 참가하고 N개의 깃발이 존재할 때, N 번째 선수까지 진행하여 완료된 상태에서 백색이 위로 놓여있는 깃발의 수가 몇 개인지 알아보자.

입력

첫 번째 줄에 출전한 학생의 수이자, 깃발의 개수인 N(1 ≤ N ≤ 2,100,000,000)이 주어진다.

출력

첫 번째 줄에 N 번째 선수까지 진행한 후의 상태의 깃발 중 백색이 위로 놓여있는 깃발의 수를 출력한다.

예제 입력 1 복사

3

예제 출력 1 복사

1

예제 입력 2 복사

24

예제 출력 2 복사

4

 

문제풀이(1)

모든 깃발이 위가 청색일 때, N명의 사람이 i배수 만큼 뒤집게된다. 이때, 해당 번호의 약수가 홀수 인것은 백기가 된다.
백기의 개수를 구하는 문제이기 때문에 해당 번호의 약수가 홀수인 것을 찾으면 될 것이다.
1 = 1번 = 백기, 2 = 2번 = 청기, 3 = 2번 = 청기, 4 = 3번 = 백기 ...
루트 i 가 정수일 때, 약수가 홀수로 나오게 된다.
시간제한이 1초이고, N은 최대 21억 번이기 때문에 일반적인 반복문을 순회할 경우 21초 걸리게된다.
그렇기 때문에 루트 i가 N보다 작을 경우를 카운트 해주면 된다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const N = Number(require("fs").readFileSync(filePath).toString().trim());

// 1 = 백기, 2 = 청기기 때문에 초기 값을 1로 둔다.
let answer = 1;

for (let i = 2; i * i <= N; i++) {
  answer++;
}

console.log(answer);

https://www.acmicpc.net/problem/11507

 

11507번: 카드셋트

예제1 : 12 12 11 13은 잃어버린 P카드 :  12개, K : 12개, H : 11개, T : 13라는 뜻이다. 예제2 : 같은 카드(H02)가 존재하므로 GRESKA을 출력하였다.

www.acmicpc.net

문제

최근에 진솔이는 로봇 공학을 하기 시작했다. 그래서 포커 카드가 완전한 세트인지 확인하는 로봇을 만들기로 결심했다.

그는 프로그램을 작성하는 일을 분담했다. 그 프로그램은 카드의 모양(스페이드(♠), 하트(♡), 다이아몬드(♢), 클럽(♣))을 인식하는 것이다. 문제를 간단하게 하기 위해서 모든 카드는 하나의 모양과 하나의 숫자를 가진다고 가정한다.

여기서 그 모양은 실제 그림 대신 문자로 대체한다. P,K,H,T에 해당한다. 그리고 숫자는 1~13에 해당하는 정수이다. 로봇은 각각의 카드를 TXY의 형태로 '카드 이름'을 정하는데 T는 모양에 해당하고 XY는 숫자에 해당한다. 만약 만약 숫자가 1자리 숫자이면 X=0에 해당한다. ex) 01.

만약에 모양이 P이고 숫자가 9이면 P09이다.

완벽한 카드 한 세트는 52개로 이루어져 있다. (4 (모양)x 13(숫자))

로봇은 모든 카드의 '카드이름'을 읽고 문자열 S로 결합한다.

이제 진솔이가 프로그래밍 하는 것을 도와주자.  문자열을 읽어 얼마나 많은 카드를 잃어버렸는지 세면 된다.

만약에 2개의 같은 카드가 존재한다면 GRESKA이라고 출력하면 된다.

입력

오직 1줄만 문자열 S(1 ≤ |S| ≤ 1000)가 들어온다. 이것은 현재 가지고 있는 카드 이름에 해당한다.

출력

만약 똑같은 카드가 존재한다면 GRESKA을 출력한다.

그렇지 않으면 4개의 정수를 공백 문자로 구분하여 출력한다. 각각 P, K, H, T에 해당한다.

예제 입력 1 복사

P01K02H03H04

예제 출력 1 복사

12 12 11 13

예제 입력 2 복사

H02H10P11H02

예제 출력 2 복사

GRESKA

 

문제풀이(1) - 런타임 에러

P, K, H, T의 카드가 각 13개씩 존재하는데 입력에 중복되지 않은 각 카드의 종류별로 개수를 세어주면 될 것이다.
1. 3자리씩 끊어서 카드의 총 개수를 파악한다.
2. 카드의 총 개수 중 중복여부를 확인한다. (중복일 경우 'GRESKA' 출력)
3. 카드 종류별로 13-가지고 있는 카드수 를 계산한뒤 출력한다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const input = require("fs").readFileSync(filePath).toString().trim();

// 전체 카드 목록
const totalCardList = [];
// 중복된 카드 여부
let flag = false;

// 카드 등록
for (let i = 0; i < input.length; i += 3) {
  const card = input.slice(i, i + 3);

  if (!totalCardList.includes(card)) {
    totalCardList.push(card);
  } else {
    flag = true;
    break;
  }
}

if (flag) {
  console.log("GRESKA");
} else {
  const answer = { P: 13, K: 13, H: 13, T: 13 };
  for (let i = 0; i < totalCardList.length; i++) {
    answer[totalCardList[i][0]] -= 1;
  }
  console.log(Object.values(answer).join(" ").trim());
}

 

문제풀이(2)

문제풀이(1)도 문제는 풀렸지만 입력단계에서 런타임 에러가 발생하는 문제였다.
입력을 readline으로 변경하니 해결되었다.

const readline = require("readline");
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

// 전체 카드 목록
const totalCardList = [];
// 중복된 카드 여부
let flag = false;

rl.on("line", function (line) {
  const input = line.trim();

  // 카드 등록
  for (let i = 0; i < input.length; i += 3) {
    const card = input.slice(i, i + 3);

    if (!totalCardList.includes(card)) {
      totalCardList.push(card);
    } else {
      flag = true;
      break;
    }
  }

  if (flag) {
    console.log("GRESKA");
  } else {
    const answer = { P: 13, K: 13, H: 13, T: 13 };
    for (let i = 0; i < totalCardList.length; i++) {
      answer[totalCardList[i][0]] -= 1;
    }
    console.log(Object.values(answer).join(" ").trim());
  }

  rl.close();
}).on("close", function () {
  process.exit();
});

https://www.acmicpc.net/problem/12782

 

12782번: 비트 우정지수

진홍이는 숫자를 좋아한다. 오늘도 숫자를 가지고 놀던 진홍이는 두 숫자의 비트 우정지수를 구해보았다. 비트 우정지수란, 10진법으로 나타낸 두 정수를 이진수로 나타내었을 때, 두 숫자를 같

www.acmicpc.net

문제

진홍이는 숫자를 좋아한다. 오늘도 숫자를 가지고 놀던 진홍이는 두 숫자의 비트 우정지수를 구해보았다. 비트 우정지수란, 10진법으로 나타낸 두 정수를 이진수로 나타내었을 때, 두 숫자를 같게 만드는데 필요한  최소 연산 횟수를 말한다. 연산의 종류는 다음과 같다.

  1. 하나의 이진수에서 임의의 자리의 숫자를 0 또는 1로 바꾼다.
  2. 하나의 이진수에서 서로 다른 자리에 있는 두 숫자의 위치를 바꾼다.

예를 들어, 10진수 11과 12의 비트 우정지수를 구해보자. 11을 이진수로 나타내면 1011이고, 12를 이진수로 나타내면 1100이다. 1011에서 2의 자리를 0으로 바꾸고(1011 -> 1001), 1의 자리와 4의 자리의 숫자를 서로 바꾸면(1001 -> 1100) 1100이 된다. 즉, 1011을 1100으로 바꾸는 최소 연산 횟수는 두 번으로, 11과 12의 비트 우정지수는 2가 된다.

진홍이는 어떤 두 수가 주어졌을 때 두 수의 비트 우정지수를 구하는 프로그램을 만들고 싶다. 하지만, 아쉽게도 진홍이는 프로그래밍에 약해 10진수를 이진수로 바꾸는 것 밖에 하지 못한다. 여러분이 진홍이를 도와 두 수의 비트 우정지수를 구하는 프로그램을 만들어 주자!

입력

입력의 첫 줄에는 테스트 케이스의 개수 T(1 ≤ T ≤ 50)가 주어진다.

각 테스트케이스의 첫 번째 줄에는 두 이진수 N, M이 주어진다. N, M의 자릿수는 1,000,000을 넘지 않으며, 자릿수는 서로 같다.

출력

각 테스트 케이스마다 두 수의 비트 우정지수를 출력한다.

예제 입력 1 복사

3
1011 1100
100101 110100
00110100 10010111

예제 출력 1 복사

2
1
3

 

문제풀이(1)

1011, 1100 두개의 2진수 비트 2개가 있을 때, 1011을 1100으로 바꾸는 최소 연산횟수를 구하는 문제이다.
1011 -> 1001 -> 1100으로 바뀐다고 한다.

2개 비트의 1의 개수를 구하면서 서로 자리가 다른 곳의 개수도 구한뒤 계산하면 된다고 생각했다.
2개 비트의 1의 개수가 같을 경우 (자리가 다른 곳의 개수 / 2)를 해주면 1과 0의 위치만 바꾸기 때문에 정답이 나올 것이다.
2개 비트이 1의 개수가 다를 경우 (자리가 다른 곳의 개수 - 첫번째 비트이 1의 개수 - 두번째 비트의 1의 개수) / 2 + (첫번째 비트이 1의 개수 - 두번째 비트의 1의 개수)를 하게되면,
1과 0의 차이만큼 변환을 해주고 자리를 이동하게 되는 로직이다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const input = require("fs").readFileSync(filePath).toString().trim().split("\n");

const N = Number(input.shift());
const bitArr = input.map((el) => el.split(" "));

const answer = [];

for (let i = 0; i < N; i++) {
  const [firstBit, secondBit] = bitArr[i];

  let firstBitOneCount = 0; // 첫번째 비트의 1의 개수
  let secondBitOneCount = 0; // 두번째 비트의 1의 개수
  let differentLocationCount = 0; // 다른 자리수의 개수

  for (let j = 0; j < firstBit.length; j++) {
    if (firstBit[j] === "1") firstBitOneCount++;

    if (secondBit[j] === "1") secondBitOneCount++;

    if (firstBit[j] !== secondBit[j]) differentLocationCount++;
  }

  if (firstBitOneCount === secondBitOneCount) {
    answer.push(Math.floor(differentLocationCount / 2));
  } else {
    let subtract = Math.abs(firstBitOneCount - secondBitOneCount);
    answer.push(Math.floor((differentLocationCount - subtract) / 2 + subtract));
  }
}

console.log(answer.join("\n"));

https://www.acmicpc.net/problem/16439

 

16439번: 치킨치킨치킨

첫 번째 줄에 고리 회원의 수 N (1 ≤ N ≤ 30) 과 치킨 종류의 수 M (3 ≤ M ≤ 30) 이 주어집니다. 두 번째 줄부터 N개의 줄에 각 회원의 치킨 선호도가 주어집니다. i+1번째 줄에는 i번째 회원의 선

www.acmicpc.net

문제

N명의 고리 회원들은 치킨을 주문하고자 합니다.

치킨은 총 M가지 종류가 있고 회원마다 특정 치킨의 선호도가 있습니다. 한 사람의 만족도는 시킨 치킨 중에서 선호도가 가장 큰 값으로 결정됩니다. 진수는 회원들의 만족도의 합이 최대가 되도록 치킨을 주문하고자 합니다.

시키는 치킨의 종류가 많아질수록 치킨을 튀기는 데에 걸리는 시간도 길어지기 때문에 최대 세 가지 종류의 치킨만 시키고자 합니다.

진수를 도와 가능한 만족도의 합의 최댓값을 구해주세요.

입력

첫 번째 줄에 고리 회원의 수 N (1 ≤ N ≤ 30) 과 치킨 종류의 수 M (3 ≤ M ≤ 30) 이 주어집니다.

두 번째 줄부터 N개의 줄에 각 회원의 치킨 선호도가 주어집니다.

i+1번째 줄에는 i번째 회원의 선호도 ai,1, ai,2, ..., ai,M (1 ≤ ai,j ≤ 9) 가 주어집니다.

출력

첫 번째 줄에 고리 회원들의 만족도의 합의 최댓값을 출력합니다.

예제 입력 1 복사

3 5
1 2 3 4 5
5 4 3 2 1
1 2 3 2 1

예제 출력 1 복사

13

예제 입력 2 복사

4 6
1 2 3 4 5 6
6 5 4 3 2 1
3 2 7 9 2 5
4 5 6 3 2 1

예제 출력 2 복사

25

 

문제풀이(1)

치킨의 종류는 3개이며, 치킨 선호도 점수의 최대합을 구하는 문제이다.
아래와 같은 input이 있을 때, 1번 = 6번째 치킨, 점수 6점 | 2번 = 1번째 치킨, 점수 6점 | 3번 = 4번째 치킨, 점수 9점이다.
이때, 4번의 최대값은 6이지만 1, 4, 6번째 치킨 중 가장 선호도 점수가 높은 1번째 치킨의 선호도만 구할 수 있다.
완전탐색을 통해 문제를 풀 수 있다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const input = require("fs").readFileSync(filePath).toString().trim().split("\n");

const [N, M] = input.shift().split(" ").map(Number);
const arr = input.map((el) => el.split(" ").map(Number));

const answer = [];

for (let i = 0; i < M - 2; i++) {
  for (let j = i + 1; j < M - 1; j++) {
    for (let k = j + 1; k < M; k++) {
      let total = 0;

      arr.forEach((el) => {
        total += Math.max(el[i], el[j], el[k]);
      });

      answer.push(total);
    }
  }
}

console.log(Math.max(...answer));

+ Recent posts