@시뮬레이션 | 1h
백준 14891.톱니바퀴와 똑같은 문제
어려운 문제는 아니고, 그냥 차근차근 풀어가면 되는 문제다.
인덱스 관리도 약간 있어서 처음에 시뮬 연습하기에 좋은 문제인 듯.
근데 문제 잘못 이해해서, 로직을 잘못 짜서 고치느라 시간이 좀 걸렸다.
문제 링크
https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWIeV9sKkcoDFAVH
구현 방법
이번 문제는 재귀 식으로 만약 3번의 왼쪽이 돌아가면, 그 함수에서 다시 왼쪽을 검사해서 돌리는 식으로 재귀적으로 풀었다.
왜냐면.. 순차적으로 돌아가는 줄 알고ㅠ
근데 재귀는 익숙하지도 않고, 혹시나 내가 예상하지 못한 결과가 나올까봐 좀 불안했다.
예전에 백준 톱니바퀴를 풀었을 때에는 그냥 왼쪽 반복문, 오른쪽 반복문으로 한번에 체크했는데 이 방식이 훨씬 깔끔하고 나은 것 같다.
문제를 처음부터 제대로 이해했으면 이렇게 풀었을 것 같다.
맞은 후 다시 반복문으로 고쳐서 제출해봤는데, 시간은 엇비슷하지만 코드가 훨씬 짜기 쉬웠다
구현 포인트
1. 톱니바퀴 수만큼의 int 배열을 만들고, check[돌아야 하는 톱니바퀴 번호] = 돌아야 하는 방향; 으로 저장한다.
재귀든, 반복문이든 돌아야 할 톱니바퀴 번호를 다 체크한 후 for문을 돌면서 check 배열 값이 0이 아닌 경우에 회전하도록 구현했다.
이 때, 회전한 후에 꼭 check 배열 값을 0으로 초기화 해주는 작업이 필요하다.
2. 맞닿아 있는 톱니바퀴는 회전 방향이 반대이다. 1과 -1로 변하기 때문에 -1을 곱해줘서 방향을 반대로 바꿔줬다.
반복문을 사용한 코드 (개인적으로 이게 더 낫다고 생각한다. 구현하기에도 + 읽기에도)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Solution_while {
private static int k, map[][], dir[][], rotateCheck[];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
StringBuilder sb = new StringBuilder();
int T = Integer.parseInt(br.readLine());
for (int t = 1; t <= T; t++) {
rotateCheck = new int[4];
k = Integer.parseInt(br.readLine());
dir = new int[k][2];
map = new int[4][8];
for (int i = 0; i < 4; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < 8; j++)
map[i][j] = Integer.parseInt(st.nextToken());
}
for (int i = 0; i < k; i++) {
st = new StringTokenizer(br.readLine());
dir[i][0] = Integer.parseInt(st.nextToken()) - 1; //자석 번호. 0-3으로 받기
dir[i][1] = Integer.parseInt(st.nextToken()); //자석 회전 방향
}
for (int i = 0; i < k; i++) {
rotationCheck(dir[i][0], dir[i][1]);
rotate();
}
sb.append("#" + t + " " + getScore() + "\n");
}
System.out.println(sb);
}
private static void rotationCheck(int idx, int direction) {
rotateCheck[idx] = direction;
int tempIdx = idx;
int reverseDir = -1 * direction;
while (tempIdx >= 1) { //왼쪽에 자석이 있을 경우에
if (map[tempIdx][6] != map[tempIdx - 1][2]) {
rotateCheck[tempIdx - 1] = reverseDir;
tempIdx--;
reverseDir *= -1;
} else {
break;
}
}
tempIdx = idx;
reverseDir = -1 * direction;
while (tempIdx < 3) { //오른쪽에 자석이 있을 경우에
if (map[tempIdx][2] != map[tempIdx + 1][6]) {
rotateCheck[tempIdx + 1] = reverseDir;
tempIdx++;
reverseDir *= -1;
} else {
break;
}
}
}
private static void rotate() {
for (int i = 0; i < 4; i++) {
if (rotateCheck[i] == 0) continue;
if (rotateCheck[i] == 1) { //시계방향
int temp = map[i][7];
for (int j = 7; j >= 1; j--)
map[i][j] = map[i][j - 1];
map[i][0] = temp;
} else { //반시계방향
int temp = map[i][0];
for (int j = 0; j < 7; j++)
map[i][j] = map[i][j + 1];
map[i][7] = temp;
}
rotateCheck[i] = 0; //값 꼭 초기화 해주기!
}
}
private static int getScore() {
int score = 0;
for (int i = 0; i < 4; i++) {
if (map[i][0] == 1)
score += Math.pow(2, i);
}
return score;
}
}
재귀를 사용한 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Solution_recursion {
private static int k, map[][], dir[][], rotateCheck[];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
StringBuilder sb = new StringBuilder();
int T = Integer.parseInt(br.readLine());
for (int t = 1; t <= T; t++) {
rotateCheck = new int[4];
k = Integer.parseInt(br.readLine());
dir = new int[k][2];
map = new int[4][8];
for (int i = 0; i < 4; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < 8; j++)
map[i][j] = Integer.parseInt(st.nextToken());
}
for (int i = 0; i < k; i++) {
st = new StringTokenizer(br.readLine());
dir[i][0] = Integer.parseInt(st.nextToken()) - 1; //자석 번호. 0-3으로 받기
dir[i][1] = Integer.parseInt(st.nextToken()); //자석 회전 방향
}
for (int i = 0; i < k; i++) {
rotationCheck(dir[i][0], dir[i][1], true);
rotationCheck(dir[i][0], dir[i][1], false);
rotateCheck[dir[i][0]] = dir[i][1];
rotate();
}
sb.append("#" + t + " " + getScore() + "\n");
}
System.out.println(sb);
}
private static void rotationCheck(int idx, int direction, boolean isLeft) {
int reverseDir = -1 * direction;
if (isLeft) {
if (idx >= 1) { //왼쪽에 자석이 있을 경우에
if (map[idx][6] != map[idx - 1][2]) {
rotationCheck(idx - 1, reverseDir, true);
rotateCheck[idx - 1] = reverseDir;
}
}
} else {
if (idx < 3) {
if (map[idx][2] != map[idx + 1][6]) {
rotationCheck(idx + 1, reverseDir, false);
rotateCheck[idx + 1] = reverseDir;
}
}
}
}
private static void rotate() {
for (int i = 0; i < 4; i++) {
if (rotateCheck[i] == 0) continue;
if (rotateCheck[i] == 1) { //시계방향
int temp = map[i][7];
for (int j = 7; j >= 1; j--)
map[i][j] = map[i][j - 1];
map[i][0] = temp;
} else { //반시계방향
int temp = map[i][0];
for (int j = 0; j < 7; j++)
map[i][j] = map[i][j + 1];
map[i][7] = temp;
}
rotateCheck[i] = 0; //값 꼭 초기화 해주기!
}
}
private static int getScore() {
int score = 0;
for (int i = 0; i < 4; i++) {
if (map[i][0] == 1)
score += Math.pow(2, i);
}
return score;
}
}
삽질 포인트
1번 톱니바퀴와 2번 톱니바퀴가 돌면, 돌고 나서 3번 톱니바퀴가 도는 줄 알고 코드를 짰다가 틀렸다.
맞물려서 하나씩 순서대로 도는게 아니라
한 시점을 기준으로 전체 접합부를 확인한 후 한꺼번에 돌린다.
끝!
'algorithm > SW Expert Academy' 카테고리의 다른 글
[SWEA] 1949.등산로 조성 (java) / DFS (0) | 2020.01.25 |
---|---|
[SWEA] 2382.미생물 격리 (java) / 시뮬레이션, BFS (0) | 2020.01.25 |
[SWEA] 2383.점심 식사시간 / 시뮬레이션 (0) | 2020.01.25 |
[SWEA] 2477.차량 정비소 / 시뮬레이션 (0) | 2020.01.15 |
[SWEA] 5653.줄기세포배양 / BFS, 시뮬레이션 (0) | 2020.01.08 |
댓글