⚠️ 유의사항
필자는 가독성과 구조화에 중점을 두고 문제를 풀이합니다.
필요하다면 클래스를 자주 사용하므로 절차지향 언어로 문제해결을 한다면 적용이 어려울 수 있습니다.
https://www.acmicpc.net/problem/15662
주어진 조건에 따라 톱니바퀴를 회전시킨 후, 12시 방향이 S극인 톱니바퀴의 개수를 구하는 문제입니다.
구현 난도가 마냥 낮지는 않지만 지문에서 설명하는 대로 구현하면 해결할 수 있는 문제입니다.
지문이 조금 아리까리하게 작성되어 있어서 이게 맞나... 하면서 여러번 지문을 돌려보고 부족한 필자의 문해력을 탓하게 된 문제이기도 합니다.
주의해야 할 사항은 아래 세 가지로 정리할 수 있습니다.
처음에는 덱을 활용하여 구현할까 생각했으나 맞물림 위치와 구해야 하는 톱니의 위치가 다르기에 효율적인 구현이라고 볼 수 없습니다.
특정 톱니의 값을 가져오는 데 굳이 추가 순회를 해서 확인하게 하는 건 품이 많이 들고, 그렇다고 톱니의 개수가 늘어나거나 줄어드는 것도 아니니까요.
톱니의 개수는 고정되어 있으니 톱니의 기본 상태를 배열에 저장해 두고 인덱스를 시작점으로 둔 뒤 회전에 따라 인덱스를 바꾸면 되겠다고 판단하였습니다.
class Gear {
private int[] gear; // 톱니바퀴의 초기 상태
private int currentPos; // 톱니바퀴의 초기 인덱스
public Gear(int[] array) {
gear = array;
currentPos = 0;
}
// 왼쪽으로 돌아가면 인덱스 값은 증가함
public void rollLeft() {
currentPos = (currentPos + 1) % 8;
}
// 오른쪽으로 가면 인덱스 값은 감소함
public void rollRight() {
if (currentPos == 0) currentPos = 7;
else currentPos -= 1;
}
// 인덱스 기준으로 각각 12시, 3시, 9시 값을 가져옴
// 3시와 9시는 톱니바퀴가 맞물리는 지점
public int get12() {
return gear[currentPos];
}
public int get3() {
return gear[(currentPos + 2) % 8];
}
public int get9() {
return gear[(currentPos + 6) % 8];
}
}
사실 필요한 모든 사항이 클래스로 구현되었기에 상술한 주의점을 생각하면서 규칙에 따라 구현하기만 하면 됩니다.
int rollCount = Integer.parseInt(reader.readLine());
for (int i = 0; i < rollCount; i++) {
String[] input = reader.readLine().split(" ");
int pos = Integer.parseInt(input[0]) - 1;
int direction = Integer.parseInt(input[1]); // 1 : 시계 방향, -1 : 반시계 방향
int[] roll = new int[gearCount];
// 현 위치를 회전시킴
roll[pos] = direction;
// 왼쪽 순회
for (int j = pos - 1; j > -1; j--) {
Gear current = gears[j];
Gear prev = gears[j + 1];
if (prev.get9() == current.get3())
break;
else {
roll[j] = -1 * roll[j + 1]; // 반대 방향으로 회전
}
}
// 오른쪽 순회
for (int j = pos + 1; j < gearCount; j++) {
Gear current = gears[j];
Gear prev = gears[j - 1];
if (prev.get3() == current.get9()) {
break;
} else {
roll[j] = -1 * roll[j - 1];
}
}
// 실제 회전
for (int j = 0; j < gearCount; j++) {
if (roll[j] == 1) gears[j].rollRight();
if (roll[j] == -1) gears[j].rollLeft();
}
}
이제 12시 방향이 S극인지 확인하고 정답을 출력해주면 끝납니다.
int count = 0;
for (int i = 0; i < gearCount; i++)
if (gears[i].get12() == 1)
count += 1;
System.out.println(count);
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int gearCount = Integer.parseInt(reader.readLine());
Gear[] gears = new Gear[gearCount];
for (int i = 0; i < gearCount; i++)
gears[i] = new Gear(Arrays.stream(reader.readLine().split("")).mapToInt(Integer::parseInt).toArray());
int rollCount = Integer.parseInt(reader.readLine());
for (int i = 0; i < rollCount; i++) {
String[] input = reader.readLine().split(" ");
int pos = Integer.parseInt(input[0]) - 1;
int direction = Integer.parseInt(input[1]); // 1 : 시계 방향, -1 : 반시계 방향
int[] roll = new int[gearCount];
// 현 위치를 회전시킴
roll[pos] = direction;
// 왼쪽 순회
for (int j = pos - 1; j > -1; j--) {
Gear current = gears[j];
Gear prev = gears[j + 1];
if (prev.get9() == current.get3())
break;
else {
roll[j] = -1 * roll[j + 1]; // 반대 방향으로 회전
}
}
// 오른쪽 순회
for (int j = pos + 1; j < gearCount; j++) {
Gear current = gears[j];
Gear prev = gears[j - 1];
if (prev.get3() == current.get9()) {
break;
} else {
roll[j] = -1 * roll[j - 1];
}
}
// 실제 회전
for (int j = 0; j < gearCount; j++) {
if (roll[j] == 1) gears[j].rollRight();
if (roll[j] == -1) gears[j].rollLeft();
}
}
int count = 0;
for (int i = 0; i < gearCount; i++)
if (gears[i].get12() == 1)
count += 1;
System.out.println(count);
}
}
class Gear {
private int[] gear;
private int currentPos;
public Gear(int[] array) {
gear = array;
currentPos = 0;
}
public void rollLeft() {
currentPos = (currentPos + 1) % 8;
}
public void rollRight() {
if (currentPos == 0) currentPos = 7;
else currentPos -= 1;
}
public int get12() {
return gear[currentPos];
}
public int get3() {
return gear[(currentPos + 2) % 8];
}
public int get9() {
return gear[(currentPos + 6) % 8];
}
}
사실 거의 똑같은 문제이고, 이 문제를 푸셨다면 14891번은 몇 줄만 고치면 맞힐 수 있습니다.
그 반대는 조금은 생각해서 풀어야겠지만요.