도비LOG(跳飛錄)

도비의 AI 엔지니어 도전기

알고리즘

[백준 1780] 종이의 개수 (실버2) Python

나쁜도비 2023. 4. 23. 20:12

https://www.acmicpc.net/problem/1780

 

1780번: 종이의 개수

N×N크기의 행렬로 표현되는 종이가 있다. 종이의 각 칸에는 -1, 0, 1 중 하나가 저장되어 있다. 우리는 이 행렬을 다음과 같은 규칙에 따라 적절한 크기로 자르려고 한다. 만약 종이가 모두 같은 수

www.acmicpc.net


문제

N×N크기의 행렬로 표현되는 종이가 있다. 종이의 각 칸에는 -1, 0, 1 중 하나가 저장되어 있다. 우리는 이 행렬을 다음과 같은 규칙에 따라 적절한 크기로 자르려고 한다.

  1. 만약 종이가 모두 같은 수로 되어 있다면 이 종이를 그대로 사용한다.
  2. (1)이 아닌 경우에는 종이를 같은 크기의 종이 9개로 자르고, 각각의 잘린 종이에 대해서 (1)의 과정을 반복한다.

이와 같이 종이를 잘랐을 때, -1로만 채워진 종이의 개수, 0으로만 채워진 종이의 개수, 1로만 채워진 종이의 개수를 구해내는 프로그램을 작성하시오.

입력

첫째 줄에 N(1 ≤ N ≤ 37, N은 3k 꼴)이 주어진다. 다음 N개의 줄에는 N개의 정수로 행렬이 주어진다.

출력

첫째 줄에 -1로만 채워진 종이의 개수를, 둘째 줄에 0으로만 채워진 종이의 개수를, 셋째 줄에 1로만 채워진 종이의 개수를 출력한다.


풀이

자른 조각 내의 숫자가 모두 동일해질 때까지 반복해야 하는 분할 정복 문제이다. 매 반복마다 9조각으로 조개야 하므로 영역을 분할할 때 분할하는 조각의 size는 분할 전 조각의 1/3이 되어야 한다. 분할이 종료되고 나면 -1로만 이루어진 조각 수, 0으로만 이루어진 조각 수, 1로만 이루어진 조각 수를 프린트해준다.

# 백준 1780 종이의 개수 실버2 https://www.acmicpc.net/problem/1780
# n x n 행렬에서, 모두 같은 수로 되어 있지 않다면 9개로 자른다.
# 분할정복
n = int(input())
graph = []
for _ in range(n):
    graph.append(list(map(int, input().split())))

minus_one_cnt = 0
zero_cnt = 0
one_cnt = 0
def divide(start_row, start_col, size):
    global minus_one_cnt, zero_cnt, one_cnt
    num = graph[start_row][start_col]

    for i in range(start_row, start_row+size):
        for j in range(start_col, start_col+size):
            if graph[i][j] != num:
                size //= 3
                divide(start_row, start_col, size)
                divide(start_row+size, start_col, size)
                divide(start_row+(2*size), start_col, size)
                divide(start_row+(2*size), start_col+size, size)

                divide(start_row+size, start_col+size, size)

                divide(start_row, start_col+size, size)
                divide(start_row, start_col+(2*size), size)
                divide(start_row+size, start_col+(2*size), size)
                divide(start_row+(2*size), start_col+(2*size), size)
                return
    else:
        if num == -1:
            minus_one_cnt += 1
        elif num == 0:
            zero_cnt += 1
        else:
            one_cnt += 1
    
divide(0,0, n)
print(minus_one_cnt, zero_cnt, one_cnt)

  divide 함수는 시작할 행 인덱스(start_row), 시작할 열 인덱스(start_col), 그리고 탐색할 영역의 크기인 size를 입력으로 받는다. 그리고 영역의 각 원소를 탐색하면서 다른 숫자를 발견하면 재귀적으로 분할을 수행한다. 이때 9개의 영역을 분할할 수 있도록, 분할할 영역별로 divide를 수행해준다. 

  만약 for문을 모두 통과했다면 영역 내의 숫자가 모두 동일하다는 것을 의미하므로, 영역을 이룬 숫자가 무엇인지에 따라서 minus_one_cnt, zero_cnt, one_cnt 를 업데이트해준다.

728x90