https://www.acmicpc.net/problem/12100
4개의 방향을 중복 순열로 가능한 가짓수를 모두 뽑아서(4^5) 각각 이동을 시키는 방법(n^2)으로 풀었다.
BFS,DFS로 푸는 방법도 있던데 이 방법은 완전탐색에 가까운 것 같다.
import sys
import collections
from copy import deepcopy
WEST, EAST, NORTH, SOUTH = 1, 2, 3, 4
def Print(lst):
for i in lst:
for j in i:
print(j, end=" ")
print("")
print("")
def move_north(board):
queue = collections.deque()
joinable = [[True for _ in range(n)] for _ in range(n)] # 한번 합쳐진 블록은 False로 표시
# 작업할 큐를 만듦
for row in range(n):
for col in range(n):
if board[row][col] != 0: # 0이 아니면 추가
queue.append([row, col])
else: # 0이면 0이 아닌 값을 땡겨와서 추가
for sub_row in range(row+1, n):
if board[sub_row][col] != 0:
board[row][col] = board[sub_row][col]
board[sub_row][col] = 0
queue.append([row, col])
break
while queue:
row, col = queue.popleft()
if 0 <= row + 1 < n:
if board[row][col] == 0 and board[row+1][col] != 0: # 처음에는 0이 아니었지만 합쳐지면서 0이 된 경우
board[row][col] = board[row+1][col] # row+1을 땡겨온다. joinable도 땡겨옴
board[row+1][col] = 0
joinable[row][col] = joinable[row+1][col]
joinable[row+1][col] = True
if joinable[row][col]:
queue.append([row, col])
elif board[row][col] == board[row+1][col]: # 합침
board[row][col] = board[row][col]*2
board[row+1][col] = 0
joinable[row][col] = False
def move_south(board):
queue = collections.deque()
joinable = [[True for _ in range(n)] for _ in range(n)]
for row in reversed(range(0, n)):
for col in range(0, n):
if board[row][col] != 0:
queue.append([row, col])
else:
for sub_row in reversed(range(0, row)):
if board[sub_row][col] != 0:
board[row][col] = board[sub_row][col]
board[sub_row][col] = 0
queue.append([row, col])
break
while queue:
row, col = queue.popleft()
if 0 <= row - 1 < n:
if board[row][col] == 0 and board[row-1][col] != 0: # 처음에는 0이 아니었지만 합쳐지면서 0이 된 경우
board[row][col] = board[row-1][col]
board[row-1][col] = 0
joinable[row][col] = joinable[row-1][col]
joinable[row-1][col] = True
if joinable[row][col]:
queue.append([row, col])
elif board[row][col] == board[row-1][col]:
board[row][col] = board[row][col]*2
board[row-1][col] = 0
joinable[row][col] = False
def move_east(board):
queue = collections.deque()
joinable = [[True for _ in range(n)] for _ in range(n)]
for row in range(n):
for col in reversed(range(0, n)):
if board[row][col] != 0:
queue.append([row, col]) # board[row][col][1] = True
else: # 값이 0이면 땡겨오고나서 큐에 추가
for sub_col in reversed(range(0, col)):
if board[row][sub_col] != 0:
board[row][col] = board[row][sub_col]
board[row][sub_col] = 0
queue.append([row, col])
break
while queue:
row, col = queue.popleft()
if 0 <= col-1 < n:
if board[row][col] == 0 and board[row][col-1] != 0: # 처음에는 0이 아니었지만 합쳐지면서 0이 된 경우
board[row][col] = board[row][col-1]
board[row][col-1] = 0
joinable[row][col] = joinable[row][col-1]
joinable[row][col-1] = True
queue.append([row, col])
elif board[row][col] == board[row][col-1]:
board[row][col] = board[row][col]*2
board[row][col-1] = 0
joinable[row][col] = False
joinable[row][col-1] = True
def move_west(board):
queue = collections.deque()
joinable = [[True for _ in range(n)] for _ in range(n)] # 한 번 합쳐진 블록은 False로 표시
# 작업할 큐를 만듦
for row in range(n):
for col in range(n):
if board[row][col] != 0: # 0이 아닌 값만 큐에 추가
queue.append([row, col])
else: # 값이 0이면 0이 아닌 것을 뒤에서 땡겨와서 그 값을 큐에 추가
for sub_col in range(col+1, n):
if board[row][sub_col] != 0:
board[row][col] = board[row][sub_col]
board[row][sub_col] = 0
queue.append([row, col])
break
while queue:
row, col = queue.popleft()
if 0 <= col+1 < n:
if board[row][col] == 0 and board[row][col+1] != 0: # 처음에는 0이 아니었지만 합쳐지면서 0이 된 경우
board[row][col] = board[row][col+1]
board[row][col+1] = 0
joinable[row][col] = joinable[row][col+1]
joinable[row][col+1] = True
if joinable[row][col]:
queue.append([row, col])
elif board[row][col] == board[row][col+1]:
board[row][col] = board[row][col]*2
board[row][col+1] = 0
joinable[row][col] = False
joinable[row][col+1] = True
###
# 중복 순열에 뽑힌 방향 순서대로 보드를 이동시키는 함수
###
def move(directions):
global maxValue
board = deepcopy(board_origin) # 원본 보드가 변경되면 안되므로 deepcopy 필요
for way in directions:
if way == WEST:
move_west(board)
elif way == EAST:
move_east(board)
elif way == NORTH:
move_north(board)
elif way == SOUTH:
move_south(board)
# 최댓값 비교
for line in board:
maxValue = max(maxValue, max(line))
###
# 동서남북을 중복을 허용하면서 재귀적으로 5가지를 뽑은 후
# count가 5가 되면 그 방향대로 이동을 시작시키는 함수
###
def get_permutation_directions(count, selected):
if count == 5:
move(selected)
return
for way in [WEST, EAST, NORTH, SOUTH]:
selected.append(way)
get_permutation_directions(count+1, selected)
selected.pop()
if __name__ == '__main__':
maxValue = 0
n = int(sys.stdin.readline())
board_origin = []
for _ in range(n):
board_origin.append(list(map(int, sys.stdin.readline().split())))
get_permutation_directions(0, [])
print(maxValue)
'알고리즘 > 브루트포스' 카테고리의 다른 글
16637. 괄호 추가하기 (2) (0) | 2020.05.12 |
---|---|
16637번. 괄호 추가하기 (0) | 2020.05.11 |
12100번. 2048 (Easy) (0) | 2020.05.04 |
17609번. 회문 (0) | 2020.04.19 |
2231. 분해합 (0) | 2019.11.20 |