2630. 색종이 만들기
TLDR#
재귀를 통한 분할정복 문제이다. 아마도 쿼드트리 알고리즘과 연관되어 있어보인다. 시작 위치와 변의 길이만 주어지면 그 안에서 4개로 쪼갤 건지, 바로 리턴할 것인지를 결정하면 될 뿐이라서 코드 작성 후 디버깅에 오랜 시간이 걸리지 않았다.
Snippet#
"""
http://boj.kr/2630
N*N 정사각형의 종이에 하얀색 또는 파란색이 각각 색칠되어있을 때 각각의 세그먼트들이 모두 하얀색 또는 파란색으로 칠해져 있을 수 있도록 세그먼트를 나눈다. 더 이상 나눌 수 없을 때까지 세그먼트를 나누었을 때 하얀색 세그먼트와 파란색 세그먼트의 개수를 구하라.
"세그먼트를 나눈다"의 정의는 종이를 (N/2)*(N/2) 크기의 작은 종이로 나누는 것을 의미한다.
"""
from sys import stdin
input = stdin.readline
g_segment = []
def recurse(
pos: tuple[int, int], # 시작지점
n: int, # 한 변의 길이
) -> tuple[int, int]:
"""
pos: 시작지점
n: 한 변의 길이
returns: (하얀 색으로 칠해진 칸, 파란색으로 칠해진 칸)
"""
global g_segment
i, j = pos[0], pos[1]
# print(i, j, n)
if n == 1:
return (0, 1) if g_segment[i][j] else (1, 0)
seg_sample = g_segment[i][j]
if all(all(seg_sample == x for x in row[j : j + n]) for row in g_segment[i : i + n]):
return (0, 1) if seg_sample else (1, 0)
# segmentation
nextn = n // 2
seg_result: tuple[tuple[int, int]] = (
recurse((i, j), nextn),
recurse((i, j + nextn), nextn),
recurse((i + nextn, j), nextn),
recurse((i + nextn, j + nextn), nextn),
)
lhs, rhs = zip(*seg_result)
return sum(lhs), sum(rhs)
if __name__ == "__main__":
n = int(input())
for _ in range(n):
g_segment.append([True if x == "1" else False for x in input().strip().split()])
result = recurse((0, 0), n)
print(result[0])
print(result[1])
Sample Input & Expected Output#
Input#
8
1 1 0 0 0 0 1 1
1 1 0 0 0 0 1 1
0 0 0 0 1 1 0 0
0 0 0 0 1 1 0 0
1 0 0 0 1 1 1 1
0 1 0 0 1 1 1 1
0 0 1 1 1 1 1 1
0 0 1 1 1 1 1 1
Expected Output#
9
7