https://www.acmicpc.net/problem/14891
14891번: 톱니바퀴
첫째 줄에 1번 톱니바퀴의 상태, 둘째 줄에 2번 톱니바퀴의 상태, 셋째 줄에 3번 톱니바퀴의 상태, 넷째 줄에 4번 톱니바퀴의 상태가 주어진다. 상태는 8개의 정수로 이루어져 있고, 12시방향부터
www.acmicpc.net
📌 작성한 코드
// 15683
const fs = require("fs");
const filePath = process.platform === "linux" ? "/dev/stdin" : "Beakjoon/Gold/test.txt";
let input = fs.readFileSync(filePath).toString().trim().split("\n");
const gears = [];
for (let i = 0; i < 4; i++) {
gears.push(input.shift().split(""));
}
const K = Number(input.shift());
const turns = input.map((val) => val.split(" ").map(Number));
const clockwise = (num, visited) => {
const first = gears[num][2];
const second = gears[num][6];
visited[num] = true;
gears[num].unshift(gears[num].pop());
if (num !== 3 && !visited[num + 1] && first !== gears[num + 1][6]) {
counterclockwise(num + 1, visited);
}
if (num !== 0 && !visited[num - 1] && second !== gears[num - 1][2]) {
counterclockwise(num - 1, visited);
}
};
const counterclockwise = (num, visited) => {
const first = gears[num][2];
const second = gears[num][6];
visited[num] = true;
gears[num].push(gears[num].shift());
if (num !== 3 && !visited[num + 1] && first !== gears[num + 1][6]) {
clockwise(num + 1, visited);
}
if (num !== 0 && !visited[num - 1] && second !== gears[num - 1][2]) {
clockwise(num - 1, visited);
}
};
for (let i = 0; i < turns.length; i++) {
const [num, d] = turns[i];
let visited = new Array(4).fill(false);
if (d === 1) {
clockwise(num - 1, visited);
} else {
counterclockwise(num - 1, visited);
}
}
const score = [1, 2, 4, 8];
let answer = 0;
for (let i = 0; i < 4; i++) {
if (gears[i][0] === "1") answer += score[i];
}
console.log(answer);
📌 풀이
톱니바퀴를 시계, 반시계 방향으로 돌리고 나서 마지막 결과가 어떻게 되는지 구하는 문제이다.
톱니바퀴들의 맞닿은 부분이 다른 극의 좌석으로 이루어져 있다면 한 부분이 회전할 때 다른 부분은 그 반대 방향으로 회전하게 된다. 그리고 2번이 회전하면서 3번을 회전시키고, 3번이 회전하면서 4번도 회전할 수 있는 상황이라는 것이다. 그러므로 한 부분이 회전할 때 조건을 확인해서 다른 톱니바퀴도 회전 시켜야 하는 것이다. 영향력이 계속 전달될 수 있으므로 재귀를 통해 구현해보았다.
시계 방향으로 회전하게 되면 맨 마지막에 있는 극이 맨 첫번째 극이 되기 때문에 뒤에서 꺼내서 앞에 넣어주면 되고, 반시계 방향은 그 반대이므로 첫번째에서 꺼내서 맨 뒤에 넣어주면 된다.
회전하는 경우에는 현재 톱니 바퀴의 왼쪽과 오른쪽 톱니 바퀴의 극을 확인 할 것이다. 왼쪽은 인덱스 [2], 오른쪽은 인덱스 [6]에 해당한다. 그러므로 왼쪽을 확인할 때는 현재 톱니바퀴의 [2]번과 다음 톱니바퀴의 [6]이 다른지 확인하고, 오른쪽을 확인할 때는 현재 톱니바퀴의 [6]과 다음 톱니바퀴의 [2]를 확인하면 된다. 두 극이 다르면 회전시에 그 옆의 톱니바퀴도 반대 방향으로 회전하게 되기 때문에 반대방향 회전 함수를 호출해주면 된다. 또한 1번 톱니바퀴는 왼쪽 톱니바퀴가 없기 때문에 1번을 회전 시킬 때는 왼쪽 톱니바퀴를 회전 시킬 필요가 없고, 4번을 회전시킬 때는 마찬가지로 오른쪽 톱니바퀴를 회전 시킬 필요가 없다.
이때 주의해야 할 것은 2번을 회전 시키고 1,3번이 그 영향을 받아 같이 움직이게 되었다고 가정해보자. 그러면 1번과 3번을 회전하는 로직이 진행되면서 그 옆에있는 2번이 또 회전하는 문제가 발생할 수 있다. 우리가 원하는 것은 그런 방식이 아니고, 물결이 퍼지듯 영향이 가는 것을 원하기 때문에 visited 배열을 사용해서 이미 회전하였는지 확인해줄 것이다.

const clockwise = (num, visited) => {
const first = gears[num][2];
const second = gears[num][6];
visited[num] = true; // 방문 처리
gears[num].unshift(gears[num].pop()); // 회전
// 맨 오른쪽이 아닐 때(4번 톱니바퀴는 인덱스 3임), 그리고 옆 톱니바퀴가 회전하지 않았을 때, 극이 다를 때 회전
if (num !== 3 && !visited[num + 1] && first !== gears[num + 1][6]) {
counterclockwise(num + 1, visited);
}
// 맨 왼쪽이 아닐 때(1번 톱니바퀴는 인덱스 0임), 그리고 옆 톱니바퀴가 회전하지 않았을 때, 극이 다를 때 회전
if (num !== 0 && !visited[num - 1] && second !== gears[num - 1][2]) {
counterclockwise(num - 1, visited);
}
};
const counterclockwise = (num, visited) => {
const first = gears[num][2];
const second = gears[num][6];
visited[num] = true;
gears[num].push(gears[num].shift()); // 시계 방향과 똑같고 방향만 반대로 돌려주기
if (num !== 3 && !visited[num + 1] && first !== gears[num + 1][6]) {
clockwise(num + 1, visited);
}
if (num !== 0 && !visited[num - 1] && second !== gears[num - 1][2]) {
clockwise(num - 1, visited);
}
};
회전이 끝난 후에 각 톱니바퀴의 0번 인덱스를 확인하고 해당 값이 S극이면('1'이면) 그에 해당하는 점수를 더해서 답을 구해준다.
const score = [1, 2, 4, 8];
let answer = 0;
for (let i = 0; i < 4; i++) {
if (gears[i][0] === "1") answer += score[i];
}
✅ 성공

'알고리즘 > 백준' 카테고리의 다른 글
| [JavaScript] 백준 골드 5 : 20055 - 컨베이어 벨트 위의 로봇 (1) | 2024.02.11 |
|---|---|
| [JavaScript] 백준 골드 4 : 16234 - 인구 이동 (1) | 2024.02.11 |
| [JavaScript] 백준 골드 5 : 15686 - 치킨 배달 (1) | 2024.02.09 |
| [JavaScript/백트래킹] 백준 실버 1 : 14889 - 스타트와 링크 (2) | 2024.02.08 |
| [JavaScript/백트래킹] 백준 골드 4 : 9663 - N-Queen (0) | 2024.02.08 |