Study/Baekjoon

[Python] Baekjoon2630: 색종이 만들기

devyoseph 2022. 2. 17. 17:29

색종이 만들기

1 초 128 MB 18801 12673 10423 69.556%

문제

아래 <그림 1>과 같이 여러개의 정사각형칸들로 이루어진 정사각형 모양의 종이가 주어져 있고, 각 정사각형들은 하얀색으로 칠해져 있거나 파란색으로 칠해져 있다. 주어진 종이를 일정한 규칙에 따라 잘라서 다양한 크기를 가진 정사각형 모양의 하얀색 또는 파란색 색종이를 만들려고 한다.

전체 종이의 크기가 N×N(N=2k, k는 1 이상 7 이하의 자연수) 이라면 종이를 자르는 규칙은 다음과 같다.

전체 종이가 모두 같은 색으로 칠해져 있지 않으면 가로와 세로로 중간 부분을 잘라서 <그림 2>의 I, II, III, IV와 같이 똑같은 크기의 네 개의 N/2 × N/2색종이로 나눈다. 나누어진 종이 I, II, III, IV 각각에 대해서도 앞에서와 마찬가지로 모두 같은 색으로 칠해져 있지 않으면 같은 방법으로 똑같은 크기의 네 개의 색종이로 나눈다. 이와 같은 과정을 잘라진 종이가 모두 하얀색 또는 모두 파란색으로 칠해져 있거나, 하나의 정사각형 칸이 되어 더 이상 자를 수 없을 때까지 반복한다.

위와 같은 규칙에 따라 잘랐을 때 <그림 3>은 <그림 1>의 종이를 처음 나눈 후의 상태를, <그림 4>는 두 번째 나눈 후의 상태를, <그림 5>는 최종적으로 만들어진 다양한 크기의 9장의 하얀색 색종이와 7장의 파란색 색종이를 보여주고 있다.

입력으로 주어진 종이의 한 변의 길이 N과 각 정사각형칸의 색(하얀색 또는 파란색)이 주어질 때 잘라진 하얀색 색종이와 파란색 색종이의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 전체 종이의 한 변의 길이 N이 주어져 있다. N은 2, 4, 8, 16, 32, 64, 128 중 하나이다. 색종이의 각 가로줄의 정사각형칸들의 색이 윗줄부터 차례로 둘째 줄부터 마지막 줄까지 주어진다. 하얀색으로 칠해진 칸은 0, 파란색으로 칠해진 칸은 1로 주어지며, 각 숫자 사이에는 빈칸이 하나씩 있다.

출력

첫째 줄에는 잘라진 햐얀색 색종이의 개수를 출력하고, 둘째 줄에는 파란색 색종이의 개수를 출력한다.

풀이

사각형 검사

현재 사각형을 기준으로 맨 왼쪽, 위 원소를 추출합니다. 그 원소를 기준으로 이제 비교를 시작합니다.

만약 첫번째 원소랑 달리지는 순간? 반복문을 멈추고 4방향으로 쪼갭니다.

 

사각형 방향 통과

반복문 끝에 다다른 경우 사각형을 더 이상 쪼개지 않고 첫번째 원소가 0인지 1인지 확인합니다.

첫번째 원소가 0이라면 하얀색 색종이에 +1, 첫번째 원소가 1이라면 파란색 색종이에 +1 합니다.

 

전체코드1

def dfs(row,col,n):
    global N,lst,white,blue

    first = lst[row][col]

    judge = True # 일단 색종이가 전부 같은 색이라고 가정

    # 모두 같은 색인지 검사하는 부분
    for i in range(row,row+n):
        for j in range(col,col+n):
            if lst[i][j] != first:
                judge = False   # 하나라도 다른 색이 있다면
                break           # 반복문 종료
        if not judge:
            break

    if not judge:
        dfs(row, col, int(n/2))  # 1 번째
        dfs(row, col + int(n/2),int(n/2))  # 2 번째
        dfs(row + int(n/2), col, int(n/2))  # 3 번째
        dfs(row + int(n/2), col + int(n/2), int(n/2))  # 4 번째
    else:
        if first: # first가 1이었을 때
            blue += 1
        else:
            white += 1


N = int(input())
white = blue = 0
lst = []

for i in range(N):
    lst.append(list(map(int,input().split())))

dfs(0,0,N)

print(white)
print(blue)

코드가 너무 자바 느낌이 나서 Pythonic하게 수정해봤습니다.

 

전체코드2

중간에 false를 통해 빠져나오는 것과 사각형 내부 원소 모두의 합을 구해서 판단하는 것의 효율이 비슷했습니다.

모두의 합이 0이라면 내부 사각형의 원소들은 모두 0이라는 뜻이며

모두의 합이 nxn이라면 모두의 합이 1로 파악할 수 있습니다.

def dfs(row, col, n):
    global N, lst, white, blue

    S = 0

    # 모두 같은 색인지 검사하는 부분
    for i in range(n):
        for j in range(n):
            S += lst[row+i][col+j]

    if S == 0:
        white += 1
    elif S == n * n:
        blue += 1
    else:
        dfs(row, col, n // 2)  # 1 번째
        dfs(row, col + n // 2, n // 2)  # 2 번째
        dfs(row + n // 2, col, n // 2)  # 3 번째
        dfs(row + n // 2, col + n // 2, n // 2)  # 4 번째


N = int(input())
white = blue = 0
lst = []

for i in range(N):
    lst.append(list(map(int, input().split())))

dfs(0, 0, N)

print(white)
print(blue)