8개의 톱니를 가지는 T개의 톱니바퀴가 일렬로 연결되어 있다. 각각의 톱니는 S극(1)과 N극(0) 중 하나를 가지고 있다. 하나의 톱니바퀴를 회전시키면 이웃하는 톱니바퀴들은 연결 상태에 따라 반대 방향으로 회전한다. 서로 다른 극으로 연결되어 있다면 같이 회전한다. 같은 극으로 연결되어 있다면 회전 하지 않는다. K번의 회전을 한 후에 모든 톱니바퀴 중에서 S극이 상단 톱니의 상태인 톱니바퀴들의 개수를 확인한다.
// 톱니바퀴들의 집합으로 이루어진 기계
Machine machine = new Machine();
// 톱니바퀴를 기계에 장착
int T = Integer.parseInt(reader.readLine());
while (T-- > 0)
machine.addGear(Arrays.stream(reader.readLine().split(""))
.mapToInt(Integer::parseInt).toArray());
// 톱니바퀴를 K번 회전
StringTokenizer tokenizer;
int K = Integer.parseInt(reader.readLine());
while (K-- > 0) {
tokenizer = new StringTokenizer(reader.readLine());
int gno = Integer.parseInt(tokenizer.nextToken()) - 1; // 회전시키는 톱니바퀴 번호
int rotate = Integer.parseInt(tokenizer.nextToken()); // 회전시키는 방향 번호
// 톱니바퀴 회전
machine.rotateGear(gno, rotate == 1 ? Rotation.CLOCKWISE : Rotation.COUNTER_CLOCKWISE);
}
// 기계에 포함된 톱니바퀴들의 상단 S극 톱니의 수 출력
result.append(machine.sumGearsTop());
public class Machine {
private final List<Gear> gears = new ArrayList<>(); // 기계에 삽입된 톱니바퀴들
/**
* 새로운 톱니바퀴를 추가한다.
* @param sawtooth 추가하는 톱니바퀴의 톱니 상대 배열
*/
public void addGear(int[] sawtooth) {
gears.add(new Gear(sawtooth));
}
/**
* 톱니바퀴를 회전시킨다. (기계에 의해 회전)
* @param gno 회전시키고자하는 톱니바퀴 번호
* @param rotation 회전시키고자하는 방향
*/
public void rotateGear(int gno, Rotation rotation) {
Gear gear = gears.get(gno); // 회전시키고자하는 톱니바퀴
// 왼쪽 톱니바퀴를 확인하고 다른 극으로 연결되어 있으면 왼쪽 톱니바퀴 회전
if (gno >= 1 && gear.moveTogether(gears.get(gno - 1), Direction.LEFT))
rotateGear(gno - 1, rotation.counter(), Direction.LEFT);
// 오른쪽 톱니바퀴를 확인하고 다른 극으로 연결되어 있으면 오른쪽 톱니바퀴 회전
if (gno + 1 < gears.size() && gear.moveTogether(gears.get(gno + 1), Direction.RIGHT))
rotateGear(gno + 1, rotation.counter(), Direction.RIGHT);
// 톱니바퀴 회전
gear.rotate(rotation);
}
/**
* 톱니바퀴를 회전시킨다. (다른 톱니바퀴에 의해 회전)
* @param gno 회전시키고자하는 톱니바퀴
* @param rotation 회전시키고자하는 방향
* @param direction 연결된 톱니바퀴를 확인하는 방향
*/
private void rotateGear(int gno, Rotation rotation, Direction direction) {
Gear gear = gears.get(gno); // 회전시키고자하는 톱니바퀴
// 왼쪽 방향으로 확인중이며 왼쪽 톱니바퀴를 확인하고 다른 극으로 연결되어 있으면 왼쪽 톱니바퀴 회전
if (direction == Direction.LEFT && gno >= 1 && gear.moveTogether(gears.get(gno - 1), direction))
rotateGear(gno - 1, rotation.counter(), direction);
// 오른쪽 방향으로 확인중이며 오른쪽 톱니바퀴를 확인하고 다른 극으로 연결되어 있으면 오른쪽 톱니바퀴 회전
else if (direction == Direction.RIGHT && gno + 1 < gears.size() && gear.moveTogether(gears.get(gno + 1), direction))
rotateGear(gno + 1, rotation.counter(), direction);
// 톱니바퀴 회전
gear.rotate(rotation);
}
/**
* 톱니바퀴들에서 상단 톱니가 S극인 톱니바퀴들의 개수를 확인한다.
* @return 상단 톱니가 S극인 톱니바퀴들의 개수
*/
public int sumGearsTop() {
return gears.stream().mapToInt(Gear::getTop).sum();
}
}
public class Gear {
private int top = 0; // 상단 톱니 index
private final int[] sawtooth; // 톱니 상태 배열
public Gear(int[] sawtooth) {
this.sawtooth = sawtooth;
}
/**
* 이웃하는 톱니바퀴와 다른 극으로 연결되어 있는지 확인한다.
* @param gear 이웃하는 톱니바퀴
* @param direction 이웃하는 위치 (현재 톱니바퀴 기준)
* @return 상극 연결 여부
*/
public boolean moveTogether(Gear gear, Direction direction) {
return direction == Direction.LEFT && getLeft() != gear.getRight() ||
direction == Direction.RIGHT && getRight() != gear.getLeft();
}
/**
* 톱니바퀴를 회전시킨다.
* @param rotation 회전 방향
*/
public void rotate(Rotation rotation) {
if (rotation == Rotation.CLOCKWISE) top = (top + 7) % 8;
else if (rotation == Rotation.COUNTER_CLOCKWISE) top = (top + 1) % 8;
}
/**
* 톱니바퀴의 상단 톱니 상태를 확인한다.
* @return 상단 톱니 상태
*/
public int getTop() {
return sawtooth[top];
}
/**
* 톱니바퀴의 좌측 톱니 상태를 확인한다.
* @return 좌측 톱니 상태
*/
private int getLeft() {
return sawtooth[(top + 6) % 8];
}
/**
* 톱니바퀴의 우측 톱니 상태를 확인한다.
* @return 우측 톱니 상태
*/
private int getRight() {
return sawtooth[(top + 2) % 8];
}
}
public enum Rotation {
CLOCKWISE(1), COUNTER_CLOCKWISE(-1);
private final int rotate;
Rotation(int rotate) {
this.rotate = rotate;
}
public Rotation counter() {
return rotate == 1 ? COUNTER_CLOCKWISE : CLOCKWISE;
}
}
public enum Direction {LEFT, RIGHT}