Notion에서 작성한 글이라, 여기에서 더 깔끔하게 보실 수 있습니다! 😮😊
(240828 14:47 수정)
cp
를 만들어놓고 복사하지 않은 채 백트래킹을 했다..popleft()
하여 변수에 값을 할당한 뒤 사용했다.from collections import deque
import sys
input = sys.stdin.readline
def cp(board):
return [r[:] for r in board]
def up(board):
for j in range(n):
blank = deque()
exist = []
for i in range(n):
if not board[i][j]: blank.append(i)
else:
if exist and exist[1] == board[i][j]:
board[exist[0]][j] <<= 1; board[i][j] = 0
blank.append(i)
exist = []
else: exist = [i, board[i][j]]
if blank and exist:
b = blank.popleft() # O(1)
exist[0] = b # exist[0] = blank[0] # deque indexing : O(n/64)
board[b][j], board[i][j] = board[i][j], 0
blank.append(i)
return board
def down(board):
for j in range(n):
blank = deque()
exist = []
for i in range(n-1, -1, -1):
if not board[i][j]: blank.append(i)
else:
if exist and exist[1] == board[i][j]:
board[exist[0]][j] <<= 1; board[i][j] = 0
blank.append(i)
exist = []
else: exist = [i, board[i][j]]
if blank and exist:
b = blank.popleft()
exist[0] = b
board[b][j], board[i][j] = board[i][j], 0
blank.append(i)
return board
def left(board):
for i in range(n):
blank = deque()
exist = []
for j in range(n):
if not board[i][j]: blank.append(j)
else:
if exist and exist[1] == board[i][j]:
board[i][exist[0]] <<= 1; board[i][j] = 0
blank.append(j)
exist = []
else: exist = [j, board[i][j]]
if blank and exist:
b = blank.popleft()
exist[0] = b
board[i][b], board[i][j] = board[i][j], 0
blank.append(j)
return board
def right(board):
for i in range(n):
blank = deque()
exist = []
for j in range(n-1, -1, -1):
if not board[i][j]: blank.append(j)
else:
if exist and exist[1] == board[i][j]:
board[i][exist[0]] <<= 1; board[i][j] = 0
blank.append(j)
exist = []
else: exist = [j, board[i][j]]
if blank and exist:
b = blank.popleft()
exist[0] = b
board[i][b], board[i][j] = board[i][j], 0
blank.append(j)
return board
def backtracking(board, d, mx):
if d == 5: return max(map(max, board))
for move in [up, down, left, right]:
nxt = move(cp(board))
if nxt == board or max(map(max, nxt))*1<<5-d <= mx: continue
mx = max(mx, backtracking(nxt, d+1, mx))
return mx
n = int(input())
board = [list(map(int, input().split())) for _ in range(n)]
print(backtracking(board, 0, max(map(max, board))))
up()
, down()
, left()
, right()
up()
을 기준으로 설명하면,for j in range(n)
을 이용했다.exist
를 이용했다. 숫자인 칸을 발견하면 exist
에 [index, value]
형태로 저장해 놓고, 그 다음 순회에서 숫자인 칸을 다시 발견한다면, 이미 발견한 숫자인 칸이 존재하며 그 값이 현재의 값과 같을 땐 merge를 수행한다. 이 때, merge를 수행한 현재의 칸은 빈 칸이 되어 blank
queue에 인덱스를 push해주고, exist
를 비워줘야 한다.exist
값이 존재할 때 (존재하지 않을 땐 이미 merge되었고 그 위치에 대한 처리가 merge 단계에서 이미 끝났다는 것을 의미하므로) 순회 중 가장 먼저 발견한 빈 칸과 그 칸을 swap해줌으로써 위로 이동한 것처럼 만들어 준다. 이 때, 기존 칸은 이동 후 빈 칸이 되기 때문에 blank
queue에 인덱스를 push해줘야 한다.backtracking()
d == 5
(풀기 전 내용, 240828 02:30)
left
, right
구현에서 틀린 부분이 있는 것 같다.현재까지 계산된 최댓값을 에서, 남은 이동횟수동안 어떻게 합쳐도 최댓값을 넘을 수 없는 상황 → return
이동 후 보드의 모양이 그대로일 때 → return
(아무런 변화 없이 이동 횟수만 1만 소모하는 것이므로)