메모리: 38396 KB, 시간: 6340 ms
구현, 브루트포스 알고리즘
폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다.
정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다.
정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다.
아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 종이는 1×1 크기의 칸으로 나누어져 있으며, 각각의 칸에는 정수가 하나 쓰여 있다.
테트로미노 하나를 적절히 놓아서 테트로미노가 놓인 칸에 쓰여 있는 수들의 합을 최대로 하는 프로그램을 작성하시오.
테트로미노는 반드시 한 정사각형이 정확히 하나의 칸을 포함하도록 놓아야 하며, 회전이나 대칭을 시켜도 된다.
첫째 줄에 종이의 세로 크기 N과 가로 크기 M이 주어진다. (4 ≤ N, M ≤ 500)
둘째 줄부터 N개의 줄에 종이에 쓰여 있는 수가 주어진다. i번째 줄의 j번째 수는 위에서부터 i번째 칸, 왼쪽에서부터 j번째 칸에 쓰여 있는 수이다. 입력으로 주어지는 수는 1,000을 넘지 않는 자연수이다.
첫째 줄에 테트로미노가 놓인 칸에 쓰인 수들의 합의 최댓값을 출력한다.
문제는 N x M 크기의 격자판에 쓰여 있는 숫자들 중, 테트로미노(정사각형 4개를 이어 붙인 도형)를 놓았을 때 테트로미노가 덮는 칸에 있는 숫자들의 합의 최댓값을 구하는 것입니다. 테트로미노는 회전하거나 대칭될 수 있습니다.
이 문제는 완전 탐색 (브루트 포스) 방법을 사용하여 해결할 수 있습니다. 가능한 모든 테트로미노 모양을 미리 정의하고, 격자판의 모든 위치에 각 테트로미노 모양을 놓아보면서 합을 계산합니다. 계산된 합 중 최댓값을 찾아 반환합니다. 핵심은 5가지 테트로미노의 모든 가능한 회전/대칭 형태를 효율적으로 생성하고, 격자판 내에서 유효한 위치에 놓는 것입니다. 주어진 코드에서는 DFS를 사용하여 테트로미노의 모든 모양을 생성하고 있습니다.
dfs() 함수: 가능한 테트로미노 모양 생성dfs() 함수는 깊이 우선 탐색(DFS)을 사용하여 가능한 모든 테트로미노 모양을 생성합니다. 이 함수는 (0, 0)에서 시작하여 상, 하, 좌, 우 방향으로 이동하며 정사각형을 추가합니다.deque)를 사용하여 탐색을 관리하고, 현재까지 만들어진 테트로미노 모양(shape)을 큐에 저장합니다.shape의 길이가 4가 되면 (정사각형 4개), 테트로미노 모양이 완성된 것이므로 shapes 집합에 추가합니다. 이때, 모양을 정규화하기 위해 가장 작은 x, y 좌표를 기준으로 모든 좌표를 이동시킨 후 정렬하여 튜플 형태로 저장합니다. 이렇게 하면 회전/대칭된 동일한 모양이 중복으로 저장되는 것을 방지할 수 있습니다.shapes는 set 자료구조를 사용하여 중복된 모양을 제거합니다.board에 저장합니다.dfs() 함수를 호출하여 생성된 테트로미노 모양들을 shapes 리스트에 저장합니다.(i, j)에 대해, shapes 리스트에 있는 모든 테트로미노 모양을 놓아봅니다.answer)보다 크다면, answer를 갱신합니다.answer에 저장된 최댓값을 출력합니다.시간 복잡도:
dfs() 함수는 모든 가능한 테트로미노 모양을 생성합니다. 테트로미노는 5가지 종류가 있고, 각 종류마다 최대 8개의 회전/대칭 형태가 있을 수 있습니다 (하지만 dfs로 모든 형태를 생성하기 때문에 더 많은 탐색을 할 수 있습니다). dfs() 함수의 시간 복잡도는 상수 시간에 비례한다고 볼 수 있습니다.dfs() 함수에서 더 많은 탐색을 수행하고, 파이썬의 느린 실행 속도 때문에 시간 제한에 걸릴 가능성이 있습니다.공간 복잡도:
board 리스트는 O(N * M)의 공간을 사용합니다.shapes 리스트는 테트로미노 모양을 저장하며, 최대 O(1)의 공간을 사용합니다 (테트로미노 모양의 수는 상수).dfs() 함수에서 사용하는 큐는 최악의 경우 O(1)의 공간을 사용합니다.import sys
from collections import deque
input = sys.stdin.readline
directions = [(1,0),(-1,0),(0,1),(0,-1)]
def dfs():
shapes = set()
q = deque()
q.append([(0,0)])
while q:
shape = q.popleft()
if len(shape) == 4:
min_x = min(x for x, _ in shape)
min_y = min(y for _, y in shape)
temp = tuple(sorted((x-min_x, y-min_y) for x,y in shape))
shapes.add(temp)
continue
for x, y in shape:
for dx, dy in directions:
nx, ny = x + dx, y + dy
if (nx, ny) not in shape:
q.append(shape + [(nx, ny)])
return list(shapes)
n,m = map(int, input().split())
board = []
for i in range(n):
board.append(list(map(int, input().split())))
shapes = dfs()
answer = 0
for i in range(n):
for j in range(m):
for shape in shapes:
total = 0
can_shape = True
for dx, dy in shape:
x, y = i + dx, j + dy
if 0 <= x < n and 0 <= y < m:
total += board[x][y]
else:
can_shape = False
break
if can_shape and total > answer:
answer = total
print(answer)