한 번 명령이 주어질 때 톱니바퀴들이 연쇄적으로 어떻게 회전할지에 대해 생각해보고 그대로 만들면 된다.
톱니바퀴들을 collections의 deque로 저장해서 반시계방향 회전, 시계방향 회전을 쉽게 만들었다. (rotate)
반시계, 시계 방향이 잘 와닿지 않아서 왼쪽, 오른쪽 방향 회전이라고 대충 이름붙였다.
방법은 두 가지가 있다. 하나는 반복문, 하나는 재귀.
코드는 재귀가 더 깔끔해보이지만 실행시간은 완전히 똑같았다.
재귀에 익숙해지지 않는다면 좀 처음부터 와닿긴 힘들고, 반복문이 더 이해하기 쉬운 듯 하다.
# 반복문
각 톱니바퀴의 회전 여부(-1, 0, 1)를 담을 move 리스트를 만들고,
모든 톱니바퀴들의 회전 여부를 검사하고 난 후에 move 대로 회전한다.
import sys from collections import deque def calc(): ret = 0 for i in range(4): if wheel[i][0] == '1': ret += 1 * pow(2, i) return ret def start(num, direction): move = [0] * 4 # 톱니바퀴들의 회전 여부를 담을 move 리스트 move[num] = direction # 일단 주어진 톱니바퀴는 무조건 회전 # 왼쪽 톱니바퀴들이 회전하는지? next_num, next_di = num, direction # 원본 보존을 위해 next 변수 사용 (오른쪽 톱니바퀴들도 봐야 하기 때문에) while 0 <= next_num-1: # next_num-1 이 회전하는지 안하는지를 볼 것임 if wheel[next_num][6] != wheel[next_num-1][2]: next_di = -next_di move[next_num-1] = next_di next_num -= 1 else: # 움직이지 않으면 바로 빠져나온다 break # 오른쪽 톱니바퀴들이 회전하는지? next_num, next_di = num, direction while next_num+1 < 4: if wheel[next_num][2] != wheel[next_num+1][6]: next_di = -next_di move[next_num+1] = next_di next_num += 1 else: break # move 리스트에 작성한 대로 실제로 톱니바퀴를 돌림 for n, direction in enumerate(move): if direction != 0: wheel[n].rotate(direction) if __name__ == '__main__': input = sys.stdin.readline wheel = [deque(input()[:-1]) for _ in range(4)] K = int(input()) order = [list(map(int, input().split())) for _ in range(K)] for num, direction in order: start(num-1, direction) print(calc())
# 재귀
톱니바퀴 번호 n과 방향 di을 매개변수로 넣어 매번 move_left 함수를 호출하고
함수 내에서는 n이 아닌 n-1 이 회전하는지 확인한다. (if wheel[n][6] != wheel[n-1][2])
회전할 수 있다면 n-1 을 매개변수로 다시 move_left 함수를 호출한다.
재귀에서 돌아올 때 rotate를 실행한다. (위에서 말했듯이 n이 아닌 n-1이 회전하는지 확인했으므로, n-1을 회전시킨다)
n이 아닌 n-1 부터 회전시켰으므로 마지막으로 n을 회전시키고 프로그램을 종료한다.
(n-1 -> n+1, move_left -> move_right 동일)
import sys from collections import deque def calc(): ret = 0 for i in range(4): if wheel[i][0] == '1': ret += 1 * pow(2, i) return ret def move_left(n, di): if n < 1: return if wheel[n][6] != wheel[n-1][2]: move_left(n-1, -di) wheel[n-1].rotate(di) def move_right(n, di): if 2 < n: return if wheel[n][2] != wheel[n+1][6]: move_right(n+1, -di) wheel[n+1].rotate(di) def start(num, direction): move_left(num-1, -direction) move_right(num-1, -direction) wheel[num-1].rotate(direction) if __name__ == '__main__': input = sys.stdin.readline wheel = [deque(input()[:-1]) for _ in range(4)] K = int(input()) # K번의 명령어 order = [list(map(int, input().split())) for _ in range(K)] for num, direction in order: start(num, direction) print(calc())
'알고리즘 > 시뮬레이션' 카테고리의 다른 글
16235번. 나무 재테크 (0) | 2020.04.20 |
---|---|
15685번. 드래곤 커브 (0) | 2020.04.16 |
14503번. 로봇 청소기 (0) | 2020.04.13 |
SWEA 2383번. 점심 식사시간 (0) | 2020.04.11 |
14890번. 경사로 (0) | 2020.04.08 |