14891번: 톱니바퀴
총 8개의 톱니를 가지고 있는 톱니바퀴 4개가 아래 그림과 같이 일렬로 놓여져 있다. 또, 톱니는 N극 또는 S극 중 하나를 나타내고 있다. 톱니바퀴에는 번호가 매겨져 있는데, 가장 왼쪽 톱니바퀴
www.acmicpc.net
톱니바퀴는 총 4개로 각각 8개의 톱니를 가지고 있으며 톱니는 N극(0), S극(1) 중 하나이다.
각 톱니바퀴는 맞닿은 톱니의 극이 같은 극이면 회전하지 않고, 서로 다른 극이면 회전하는 톱니와 반대 방향으로 회전한다. 톱니바퀴 초기 상태와 톱니바퀴를 회전시킨 정보가 주어졌을 때, 최종 상태를 구하는 것이 문제이다.
1. 입력 저장하기 & 그 외 필요한 변수 생성
입력으로 톱니바퀴의 초기 상태가 주어지는데,
톱니바퀴는 위와 같이 총 4개이며 각각 8개의 톱니가 있기 때문에 `int[4][8]`의 2차원 배열로 저장할 수 있다.
한 가지 더 필요한 것은 톱니바퀴들의 회전 정보이다.
한 톱니바퀴가 회전할 때 회전하는 톱니바퀴의 좌우측의 맞닿은 톱니의 극에 따라 맞닿은 톱니바퀴가 회전할수도, 회전하지 않을 수도 있다. 그래서 총 4개의 톱니바퀴의 회전 정보를 담은 1차원 배열을 생성했다.
static int[][] gear = new int[4][8]; // 톱니바퀴 상태
static int[] d = new int[4]; // 톱니바퀴 회전 정보
static int gearNum = 0; // 회전하는 톱니의 번호
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int k = 0; // 회전 횟수
int rotate = 0; // 회전 방향
int answer = 0;
for(int i=0; i<4; i++) {
String s = br.readLine();
for(int j=0; j<8; j++) {
//BufferedReader를 통해 문자열로 입력을 받았기 때문에 int로 바꿔서 저장하기
gear[i][j] = s.charAt(j) - '0';
}
}
k = Integer.parseInt(br.readLine());
}
2. 맞닿은 톱니바퀴의 회전 여부 & 회전시 회전 방향 확인하기
입력으로 주어진 톱니바퀴가 회전할 때 맞닿은 톱니바퀴의 극에 따라 회전 여부와 회전 방향이 결정된다.
그리고 회전하게 되면 그 옆에 맞닿은 톱니바퀴도 회전 여부를 확인해줘야 한다.
이미지에서 왼쪽부터 순서대로 1번, 2번, 3번,4번 이라고 했을 때, 회전하는 톱니바퀴와 맞닿은 톱니바퀴는 좌측 / 우측 이렇게 두개이다.
좌측을 먼저 살펴보면 나의(2번 톱니바퀴) 6번 톱니와 좌측 톱니바퀴의 2번 톱니가 맞닿아 있다. (연두색 점선)
마찬가지로 우측은 나의(2번 톱니바퀴) 2번 톱니와 우측 톱니바퀴의 6번 톱니가 맞닿아 있다. (하늘색 점선)
이를 활용해
좌측은 나의(2번) 6번 톱니와 좌측(1번) 톱니바퀴의 2번 톱니가 다른 극인지 확인하면 되고,
우측은 나의(2번) 2번 톱니와 우측 톱니바퀴의 6번 톱니가 다른 극인지 확인하면 회전 여부를 알 수 있다.
회전할 때는 회전하는 톱니바퀴(이미지에서는 2번)와 반대 방향으로 회전하기 때문에 회전하는 톱니바퀴의 회전방향에
-(마이너스)를 붙여서 저장해주면 된다.
public static void checkRotate(int gearNum) {
//좌측 톱니바퀴 회전 확인
for(int i=gearNum; i>0; i--) {
if(gear[i][6] != gear[i-1][2]) {
// 내 회전 방향과 반대로 회전
d[i-1] = -d[i];
}
else break;
}
//우측 톱니바퀴 회전 확인
for(int i=gearNum; i<3; i++) {
if(gear[i][2] != gear[i+1][6]) {
// 내 회전 방향과 반대로 회전
d[i+1] = -d[i];
}
else break;
}
}
톱니바퀴들이 연이어서 회전하게 될 수도 있기 때문에 for문을 통해서 좌측과 우측 모두 각 방향 끝까지 톱니들의 회전 여부를 확인한다.
3. 톱니바퀴 회전
모든 톱니바퀴들의 회전 방향을 알게 되었다면 그에 따라 톱니바퀴를 회전 시킨다.
시계 방향 회전은 배열의 관점에서 보면 한칸씩 오른쪽으로 이동하는 것으로 현재 인덱스의 값이 다음 인덱스에 저장되게 된다.
이 때,
arr[i+1] = arr[[i];
이렇게 값을 옮기게 되면 i+2번째에 i+1번째 값이 들어가야 하는데, 그 값이 이미 덮여씌여져 버렸기 때문에 문제가 발생한다. 그래서 0번부터가 아니라 뒤에서부터 내려오면서 값을 옮겨 주었다.
반시계 방향은 배열의 관점에서 보면 한칸씩 왼쪽으로 이동하는 것으로 현재 인덱스의 값이 이전 인덱스의 값에 저장되게 된다.
arr[i-1] = arr[i];
이렇게 값을 옮기게 되면 시계 방향 회전과 같은 이유로 문제가 발생하게 된다. 그래서 0번부터 올라가면서 값을 옮겨 주었다.
public static void rotateGear() {
for(int i=0; i<4; i++) {
//시계 방향 회전
if(d[i] == 1) {
int temp = gear[i][7];
for(int j=7; j>0; j--) {
gear[i][j] = gear[i][j-1];
}
gear[i][0] = temp;
d[i] = 0; // 회전이 끝났으면 0으로 초기화 해 회전이 없음을 명시
}
//반시계 방향 회전
else if(d[i] == -1) {
int temp = gear[i][0];
for(int j=0; j<7; j++) {
gear[i][j] = gear[i][j+1];
}
gear[i][7] = temp;
d[i] = 0; // 회전이 끝났으면 0으로 초기화 해 회전이 없음을 명시
}
}
}
4. 전체 코드
문제에서 주어진 설명에 따라 톱니바퀴가 회전하는 전체적인 로직을 정리하면 이렇게 정리할 수 있다.
1. k번만큼 회전 반복
1-1. 입력으로 주어진 톱니바퀴 회전
1-2. 회전하는 톱니바퀴와 맞닿은 톱니바퀴의 회전 여부 확인 & 회전시 회전 방향 확인
1-3. 톱니바퀴 회전
톱니바퀴는 1번부터 시작하고 있는데, 톱니바퀴 정보를 저장한 배열은 0번부터 시작하기 때문에 이를 맞춰주기 위해
회전할 톱니바퀴 번호에서 -1을 해 번호를 맞춰줬다.
d[gearNum-1] = rotate;
checkRotate(gearNum-1);
import java.io.*;
import java.util.*;
public class Main {
static int[][] gear = new int[4][8];
static int[] d = new int[4];
static int gearNum = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int k = 0;
int rotate = 0;
int answer = 0;
for(int i=0; i<4; i++) {
String s = br.readLine();
for(int j=0; j<8; j++) {
gear[i][j] = s.charAt(j) - '0';
}
}
k = Integer.parseInt(br.readLine());
for(int i=0; i<k; i++) { // k번만큼 회전 반복
st = new StringTokenizer(br.readLine());
gearNum = Integer.parseInt(st.nextToken()); // 회전할 톱니바퀴 번호
rotate = Integer.parseInt(st.nextToken()); // 회전 방향
d[gearNum-1] = rotate; // 회전할 톱니바퀴의 회전 정보 저장
checkRotate(gearNum-1); // 맞닿은 톱니바퀴 회전 여부 확인
rotateGear(); // 톱니바퀴 회전
}
if(gear[0][0] == 1) answer += 1;
if(gear[1][0] == 1) answer += 2;
if(gear[2][0] == 1) answer += 4;
if(gear[3][0] == 1) answer += 8;
System.out.println(answer);
}
public static void checkRotate(int gearNum) {
//좌측 톱니바퀴 회전 확인
for(int i=gearNum; i>0; i--) {
if(gear[i][6] != gear[i-1][2]) {
// 내 회전 방향과 반대로 회전
d[i-1] = -d[i];
}
else break;
}
//우측 톱니바퀴 회전 확인
for(int i=gearNum; i<3; i++) {
if(gear[i][2] != gear[i+1][6]) {
// 내 회전 방향과 반대로 회전
d[i+1] = -d[i];
}
else break;
}
}
public static void rotateGear() {
for(int i=0; i<4; i++) {
//시계 방향 회전
if(d[i] == 1) {
int temp = gear[i][7];
for(int j=7; j>0; j--) {
gear[i][j] = gear[i][j-1];
}
gear[i][0] = temp;
d[i] = 0;
}
//반시계 방향 회전
else if(d[i] == -1) {
int temp = gear[i][0];
for(int j=0; j<7; j++) {
gear[i][j] = gear[i][j+1];
}
gear[i][7] = temp;
d[i] = 0;
}
}
}
}
'알고리즘 문제풀이 > 백준' 카테고리의 다른 글
[백준 7568] 덩치 (0) | 2023.02.05 |
---|---|
[백준 1187] 단어 정렬 (0) | 2023.01.30 |
[백준 4153] 직각삼각형 (0) | 2023.01.27 |
[백준 1157] 단어 공부 (0) | 2023.01.25 |
[백준 2475] 검증수 (0) | 2023.01.25 |
댓글