-
고고학 최고의 발견코딩 테스트/Level 3 2022. 12. 11. 22:03반응형
https://school.programmers.co.kr/learn/courses/30/lessons/131702
고고학 최고의 발견 연습문제 Lv. 3 62명 4%
요약
첫 번째 줄이 결정되면, 두 번째 줄도 1가지 케이스로 결정된다.
첫 번째 줄의 모든 케이스를 전수조사(BF)한다.꽤 힘들게 풀었다 ㅠ,.ㅠ 레벨 3 맞음?
첫 줄이 결정되면 다음 줄의 답도 결정된다.
(상하좌우 방향은 관계 없다.)첫 줄이 3, 0, 3, 0 으로 결정되어 있다면
다음 줄은 1, 0, 1, 0 회전하는 케이스만 존재한다.그럼 첫 줄은 어떻게 결정할까?
첫 줄과 두 번째 줄은 서로 영향을 주기 때문에..
복잡한 문제다.첫 줄을 3, 3, 3, 0 에서 1번 턴을 해서
0, 0, 0, 0 으로 만들었더라도
두 번째 줄의 상황에 따라 최적의 해가 아닐 수가 있다.가장 얄팍한 해결책은
첫 번째 줄과 두 번째 줄의 '모든' 케이스를 체크해서
첫 번째 줄을 0, 0, 0, 0 으로 만드는 최소의 회전 수를 찾는 방법이다.경우의 수는 4**8 = 65536, 코드는 작동했으나,
당연히 시간제한.코드가 작동하는 걸 확인했으니
이것을 어떻게 최적화할까..첫 줄의 모든 경우의 수를 뽑으면 4**4 = 256
이 정도는 BF(전수조사) 해볼 만한 숫자다.첫 줄의 모든 케이스를 만든 뒤,
이를 바탕으로 다음 줄을 결정하고.
마지막 줄까지 결정되면
전체가 0이 맞는지 확인하고
턴 수의 최솟값을 모으면 답이 나온다.첫 줄의 성공 여부을 먼저 확인하지 않고,
마지막으로 미루는 것이 오히려 간단하다.다음 줄 결정에
복잡한 연산이 필요 없기 때문에
가능한 시나리오이다.from copy import deepcopy def solution(clocks): def mask_generator(): # 0 번 라인의 시계 바늘을 얼마나 돌릴 지 모든 경우를 만듬 for i in range(4 ** length): mask = [] while i: mask.append(i % 4) i //= 4 yield mask + [0] * (length - len(mask)) def check_all(board): # 모든 시계의 0시 체크 for row in board: for each in row: if each != 0: return False return True def turn_clock(y, x, time, board): # 시계 바늘을 돌려준다. for dy, dx in ((-1, 0), (0, -1), (0, 0), (0, 1), (1, 0)): if 0 <= (ny := y + dy) < length and 0 <= (nx := x + dx) < length: board[ny][nx] = (board[ny][nx] + time) % 4 def turn_line(line_num, board): # 윗 줄의 시계 바늘에 따라 아래 시계의 바늘 회전 turns = 0 for index, each in enumerate(board[line_num - 1]): if each > 0: turn_num = 4 - each turn_clock(line_num, index, turn_num, board) turns += turn_num return turns def solve(): min_turn = float("inf") for mask in mask_generator(): # 모든 경우를 만듬. board = deepcopy(clocks) # 2차원 배열의 복사에 딥카피 필요. for index, turn_num in enumerate(mask): # mask를 board에 적용. 0번 줄 회전. turn_clock(0, index, turn_num, board) # 이거 삽질이다. 그냥 mask를 바로 1열에 turns = sum(mask) # mask의 합 = 지금까지 회전수 for line_num in range(1, length): turns += turn_line(line_num, board) if check_all(board): # 체크 min_turn = min(min_turn, turns) return min_turn length = len(clocks) return solve()
코드를 조금 수정했다...
product 를 잊고 있었다.
그리고 마지막 줄만 체크하면 되는데...from copy import deepcopy from itertools import product def solution(clocks): def check_row(row): # 시계의 0시 체크 for each in row: if each != 0: return False return True def turn_clock(y, x, time, board): # 시계 바늘을 돌려준다. for dy, dx in ((-1, 0), (0, -1), (0, 0), (0, 1), (1, 0)): if 0 <= (ny := y + dy) < length and 0 <= (nx := x + dx) < length: board[ny][nx] = (board[ny][nx] + time) % 4 def turn_line(line_num, board): # 윗 줄의 시계 바늘에 따라 아래 시계의 바늘 회전 turns = 0 for index, each in enumerate(board[line_num - 1]): if each > 0: turn_num = 4 - each turn_clock(line_num, index, turn_num, board) turns += turn_num return turns def solve(): min_turn = float("inf") for mask in product(range(4), repeat=length): # 모든 경우를 만듬. board = deepcopy(clocks) # 2차원 배열의 복사에 딥카피 필요. for index, turn_num in enumerate(mask): # mask를 board에 적용. 0번 줄 회전. turn_clock(0, index, turn_num, board) turns = sum(mask) # mask의 합 = 지금까지 회전수 for line_num in range(1, length): turns += turn_line(line_num, board) if check_row(board[length - 1]): min_turn = min(min_turn, turns) return min_turn length = len(clocks) return solve()
반응형