-
알고스팟 : 시계 맞추기 (완전 탐색, 최적의 해)알고리즘 2022. 7. 3. 21:30
완전탐색으로 시계를 모두 12시로 맞추는 모든 경우의 수를 구하고 그 중 스위치를 누른 최소의 갯수를 구하려고 했으나 시간초과가 발생하였다.
import math inf = math.inf switches = [ [0, 1, 2], [3, 7, 9, 11], [4, 10, 14, 15], [0, 4, 5, 6, 7], [6, 7, 8, 10, 12], [0, 2, 14, 15], [3, 14, 15], [4, 5, 7, 14, 15], [1, 2, 3, 4, 5], [3, 4, 5, 9, 13] ] def is_aligned_clock(clock) : for time in clock : if time != 12 : return False return True def push_switch(clock, switch_num): for i in range(len(switches[switch_num])) : clock[switches[switch_num][i]] += 3 if clock[switches[switch_num][i]] == 15 : clock[switches[switch_num][i]] = 3 def match_clock (clock, switch_num) : if switch_num == 10 : if is_aligned_clock(clock): return 0 else : return inf result = inf if len(switches[switch_num]) ==1 : cnt = 4 - ((clock[switches[switch_num]]//3)% 4) return min(result, cnt + match_clock(clock, switch_num + 1)) for i in range(4) : result = min(result, i + match_clock(clock, switch_num+1)) push_switch(clock, switch_num) return result c = int(input()) for _ in range(c): clock = list(map(int, input().split())) answer = match_clock(clock, 0) if answer == inf: print(-1) else : print(answer)
시간초과 생각을 해보니 이 문제에서는 스위치에 따라 영향을 받는 시계가 주어졌는데 여기서 단일 시계를 조작하는 스위치, 즉 하나의 스위치만 조작할 수 있는 시계를 보니 1, 4, 9번 스위치에 8, 11, 12, 13번 시계가 존재 했다. 여기서 8번 시계와 12번 시계는 스위치 4번만 조작할 수 있으므로 시작단계에서 8, 12번 시계의 값이 동일하지 않다면 모든 시계를 12시로 맞출 수 없다.
재귀를 시작하기 전에 각각의 유일 시계를 조작하여 12시로 맞춘 값을 계산하고 단일 스위치 번호가 넘어올 때는 다음 스위치를 조작하도록 변경한 다음 정답이 존재할때 이전에 계산한 값을 더해줌으로서 시간초과를 해결할 수 있었다.
이 문제는 완전 탐색으로 계산하려고 하니 다음과 같이 불필요한 경우를 제외시켜줌으로서 해결할 수 있었는데, 다른 방법으로 더욱 효율을 높여 계산할 수 있을 것 같아 추가적인 공부가 필요하다!
inf = float('inf') switches = [ [0, 1, 2], [3, 7, 9, 11], [4, 10, 14, 15], [0, 4, 5, 6, 7], [6, 7, 8, 10, 12], [0, 2, 14, 15], [3, 14, 15], [4, 5, 7, 14, 15], [1, 2, 3, 4, 5], [3, 4, 5, 9, 13] ] # 하나의 시계가 조작될 수 있는 스위치 unique_clock_switch = [1, 4, 9] # 조작하는 스위치가 하나인 단일 시계 unique_clock = [11, 12, 13] # 시계가 정렬되어 있는지 확인 def is_aligned_clock(clock) : for time in clock : if time != 12 : return False return True # 스위치를 눌러 스위치가 조작하는 모든 시계를 회전 def push_switch(clock, switch_num): for i in range(len(switches[switch_num])) : clock[switches[switch_num][i]] += 3 if clock[switches[switch_num][i]] == 15 : clock[switches[switch_num][i]] = 3 # 시계를 정렬할 수 있는 경우의 수 계산 (스위치 번호를 높여주면서 깊이를 증가한다) def match_clock (clock, switch_num) : # 스위치 끝까지 오면 결과 리턴 if switch_num == 10 : if is_aligned_clock(clock): return 0 else : return inf # 단일 조작 스위치는 이전에 계산해서 더 진행하면 시계를 흐트린다. 다음 단계로 넘겨준다. if switch_num in [1, 4, 9] : return match_clock(clock, switch_num+1) result = inf # 현재 버튼을 누른 횟수 + 시계 모양에서 12시로 모든 시계를 맞추는데 버튼을 누른 횟수 (모든 경우 조회) for i in range(4) : result = min(result, i + match_clock(clock, switch_num+1)) push_switch(clock, switch_num) return result c = int(input()) for _ in range(c): clock = list(map(int, input().split())) # 8번 시계와 12번 시계가 동일해야 모든 시계를 12시로 맞출 수 있다. if clock[8] != clock[12]: print(-1) continue prior_cnt = 0 # 단일 조작 버튼은 미리 눌러서 시계를 맞추고 시작 for i in range(len(unique_clock)): cnt = (4-clock[unique_clock[i]]//3)% 4 prior_cnt+=cnt for j in range(cnt): push_switch(clock, unique_clock_switch[i]) answer = match_clock(clock, 0)+ prior_cnt if answer == inf: print(-1) else : print(answer)
'알고리즘' 카테고리의 다른 글
알고스팟 : 울타리 잘라내기 (분할정복) (0) 2022.07.04 알고스팟 : 쿼드 트리 뒤집기 (분할정복) (0) 2022.07.04 알고스팟 : 게임판 덮기 (완전탐색, 경우의 수) (0) 2022.07.03 알고스팟 : 소풍 (완전탐색, 조합) (0) 2022.07.03 알고리즘 - 7) 다익스트라 (0) 2021.05.06