백준 알고리즘

백준 - 1780번 종이의 개수 python 문제풀이 [Hellfer]

Hellfer 2023. 12. 7. 22:59
728x90

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

 

1780번: 종이의 개수

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

www.acmicpc.net

🔷 알고리즘 분류 - 분할 정복, 재귀   난이도 - 실버 2

 

분할 정복(Divide and Conquer) 알고리즘은 문제를 더 작은 부분으로 분할하여 해결하는 방법을 의미합니다. 
이 알고리즘은 크게 세 단계로 이루어져 있습니다. 

 

1. 분할(Divide): 주어진 문제를 작은 부분 문제(sub-problems)로 분할합니다. 이때 분할된 작은 문제는 원래 문제와 동일한 형태를 가집니다.


 2. 정복(Conquer): 분할된 작은 문제를 각각 해결합니다. 작은 문제의 크기가 충분히 작아질 때까지 이 과정을 반복하며, 문제의 크기가 충분히 작다면 직접 해결할 수 있습니다.


 3. 결합(Combine): 정복한 작은 문제의 해결책을 결합하여 원래 문제의 해결책을 얻습니다.

 

분할 정복 알고리즘은 이런 방식으로 문제를 쪼개어 가면서 해결하므로, 복잡한 문제를 간단하게 해결하는 데 유용합니다.

🔶문제 풀이 - 분할 정복 알고리즘을 이용한 풀이

import sys
input=sys.stdin.readline  # sys.stdin.readline은 입력 속도를 높여주는 기능입니다.

# 사용자로부터 첫 번째 숫자를 입력 받아 정수로 변환한 후 n에 저장합니다. 이는 그래프의 크기를 의미합니다.
n=int(input())

# 사용자로부터 n*n 크기의 2차원 배열을 입력 받습니다.
graph=[list(map(int,input().split())) for _ in range(n)]

# 각 숫자의 개수를 저장할 변수를 초기화합니다.
a=0
b=0
c=0

# 재귀 함수 check를 정의합니다. 이 함수는 주어진 범위 내에서 같은 숫자가 아닌 경우를 찾아내고, 
# 그 경우에는 범위를 9분할하여 다시 검사를 수행합니다.
def check(x,y,n):
    global a,b,c  # 전역 변수를 사용하기 위해 global 키워드를 사용합니다.
    paper=graph[x][y]  # x, y 위치의 숫자를 paper에 저장합니다.
    for i in range(x,x+n):
        for j in range(y,y+n):
            # 만약 paper와 다른 숫자가 발견되면, 
            if paper != graph[i][j]:
                # 9분할하여 재귀적으로 검사를 수행합니다.
                for k in range(3):
                    for l in range(3):
                        check(x+k*n//3,y+l*n//3,n//3)
                # 현재 함수를 종료합니다.
                return
    # 같은 숫자만 존재하면 해당 숫자의 개수를 증가시킵니다.
    if paper == -1:
        a+=1
    elif paper == 0:
        b+=1
    else:
        c+=1

# 초기 범위는 전체 그래프이므로 (0,0)에서 시작하여 크기는 n입니다.
check(0,0,n)

# 각 숫자의 개수를 출력합니다.
print(a)
print(b)
print(c)

🔶 문제 이해하기

예를 들어서 3x3 크기의 2차원 배열을 가지고 있다고 가정해 보겠습니다.

 

graph = [[1, 1, 0], 
         [1, 1, 0], 
         [0, 0, 0]]

 

그리고 check(0, 0, 3)을 호출한다고 하겠습니다. 여기서 (x, y)는 검사를 시작할 위치, n은 검사할 영역의 크기입니다.

처음에는 (0, 0)에서 시작하여 크기 3의 영역, 즉 전체 영역을 검사합니다. paper에는 graph [0][0]인 1이 저장됩니다.

그다음 for 루프를 이용해 (0, 0)부터 (2, 2)까지의 모든 위치를 검사합니다. 이때 graph [0][2]가 paper와 다르므로, 영역을 9 분할하여 다시 검사를 수행합니다.

9 분할은 아래와 같습니다.

 

(0, 0, 1), (0, 1, 1), (0, 2, 1)
(1, 0, 1), (1, 1, 1), (1, 2, 1)
(2, 0, 1), (2, 1, 1), (2, 2, 1)

 

왜 9 분할했을 때 위 값이 나오는지??

 

위의 튜플들 중 (0, 0, 1)은 원래 배열의 (0, 0) 위치에서 시작하여 크기가 1인 영역을 (0, 1, 1)은 (0, 1)에서 시작하여 크기가 1인 영역을 검사하라는 뜻입니다. 

 

다음 튜플 중 (0,2,1)은 배열의 (0,2) 위치에서 시작하여 크기가 1인 영역을 (1,0,1)은 (1,0)에서 시작하여 크기가 1인 영역을 검사하라는 뜻입니다.

 

이런 식으로 9 분할하여 영역을 각각 따로 재귀함수를 통해 조사하게 됩니다.

 

🤗파이팅입니다~ 여러분!!🤗

728x90