본문 바로가기
Algorithm

[분할정복/DQ] 백준 1780 종이의 개수 - Python

by jangThang 2022. 2. 16.
반응형

백준 온라인 저지

 

 

 

1. 문제 (링크 참조)

 

1780번: 종이의 개수

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

www.acmicpc.net

 

 

 

2. 문제 풀이

 -1, 0, 1로만 이루어진 종이의 개수를 세는 문제입니다. 혼합되어 있으면, 9등분하여 다시 판별합니다.

 

2022.01.29 - [Algorithm] - [Algorithm] 분할정복(DQ, Divide-and-Conquer), 각개격파 알고리즘

 

[Algorithm] 분할정복(DQ, Divide-and-Conquer), 각개격파 알고리즘

각개격파(各個擊破): 적을 하나하나 따로 떼어 무찌름  유독 외세의 침략을 많이 받았던 우리 민족의 대표적인 전술은 '매복'과 '각개격파'였습니다. 70%가 산악지형인 점을 이용해서, 산개된 적

star7sss.tistory.com

 분할정복 문제입니다. 먼저 종이가 한 가지 숫자로만 이루어져 있는지 판별하고, 섞여있으면 입력 범위를 9등분하여 재귀함수를 호출해야 합니다.

 

 

 

3. 코드

import sys
input = sys.stdin.readline

#입력
N = int(input())
paper = []
for _ in range(N):
    paper.append(list(map(int, input().split())))

minus = 0 # -1인 종이
zero = 0 # 0인 종이
plus = 0 # 1인 종이

# 같은 종이 판별기
# 모두 더했을 때 -n*n / n*n / 0만 나오면 같은 종이. 아니면 섞임
def isSamePaper(x, y, n):
    _sum = 0
    z = True
    for i in range(x, x+n):
        for j in range(y, y+n):
           _sum += paper[i][j]
           if paper[i][j] != 0: # 0이 아니면 False
                z = False

    if _sum == -1*n*n:
        return -1 # -1인 종이
    elif z == True:
        return 0 # 0인 종이
    elif _sum == n*n:
        return 1 # 1인 종이
    else:
        return 404 # 섞임

def searchPaper(a, b, n):
    x = isSamePaper(a, b, n)
    if x == 404: # 섞였을 경우, 9분할
        searchPaper(a, b, n//3) #(0,0)
        searchPaper(a + n//3, b, n//3) #(1,0)
        searchPaper(a + 2*(n//3), b, n//3) #(2,0)

        searchPaper(a, b+n//3, n//3) #(0,1)
        searchPaper(a, b+(n//3)*2, n//3) #(0,2)
        searchPaper(a+n//3, b+n//3, n//3) #(1,1)

        searchPaper(a+n//3, b+(n//3)*2, n//3) #(1,2)
        searchPaper(a+(n//3)*2, b+n//3, n//3) #(2,1)
        searchPaper(a+(n//3)*2, b+(n//3)*2, n//3) #(2,2)

    elif x == -1: #모두 -1
        global minus
        minus += 1
        # print("minus: ",minus, f"({a},{b}), {n}")
        return
    elif x == 0: #모두 0
        global zero
        zero += 1
        # print("zero: ",zero, f"({a},{b}), {n}")
        return
    else: #모두 1
        global plus
        plus += 1
        # print("plus: ",plus, f"({a},{b}), {n}")
        return

searchPaper(0, 0, N)
print(minus)
print(zero)
print(plus)

 

 입력범위를 모두 더해서 n*n이면 1, -n*n이면 -1, 0만 나왔으면 0으로 판별했습니다. 결과는 시간초과. 원래는 합이 0이면 0으로 판별했으나, 1과 -1이 동일한 개수로 있는 경우도 0으로 판별해서 코드가 복잡해졌습니다.

 

 

import sys
input = sys.stdin.readline

#입력
N = int(input())
paper = []
for _ in range(N):
    paper.append(list(map(int, input().split())))

minus = 0 # -1인 종이
zero = 0 # 0인 종이
plus = 0 # 1인 종이

# 같은 종이 판별기
def isSamePaper(x, y, n):
    for i in range(x, x+n):
        for j in range(y, y+n):
           if paper[i][j] != paper[x][y]: #맨 처음 수와 다른 수가 나오면 섞인 것
                return False
    return True #모두 같은 숫자로 이루어짐

# 분할 정복
def searchPaper(a, b, n):
    if not isSamePaper(a, b, n): # 섞였을 경우, 9분할
        searchPaper(a, b, n//3) #(0,0)
        searchPaper(a + n//3, b, n//3) #(1,0)
        searchPaper(a + 2*(n//3), b, n//3) #(2,0)

        searchPaper(a, b+n//3, n//3) #(0,1)
        searchPaper(a, b+(n//3)*2, n//3) #(0,2)
        searchPaper(a+n//3, b+n//3, n//3) #(1,1)

        searchPaper(a+n//3, b+(n//3)*2, n//3) #(1,2)
        searchPaper(a+(n//3)*2, b+n//3, n//3) #(2,1)
        searchPaper(a+(n//3)*2, b+(n//3)*2, n//3) #(2,2)

    else:
        if paper[a][b] == -1: #모두 -1
            global minus
            minus += 1
            # print("minus: ",minus, f"({a},{b}), {n}")
            return
        elif paper[a][b] == 0: #모두 0
            global zero
            zero += 1
            # print("zero: ",zero, f"({a},{b}), {n}")
            return
        else: #모두 1
            global plus
            plus += 1
            # print("plus: ",plus, f"({a},{b}), {n}")
            return

searchPaper(0, 0, N)
print(minus)
print(zero)
print(plus)

 맨 처음 수를 기준으로 잡고, 비교해서 다른 수가 나오는지 판별합니다. 이 방법은 모든 수를 비교하지 않고도, 다른 수가 나오면 바로 판별할 수 있는 장점이 있습니다.

 

 

    if not isSamePaper(a, b, n): # 섞였을 경우, 9분할
        for i in range(3):
            for j in range(3):
                searchPaper(a+(n//3)*i, b+(n//3)*j, n//3)

 위 코드에서는 풀어서 써서 조금 길어졌으나, 반복문을 이용하면 좀 더 간략하게 쓸 수 있습니다.

 

 

star가 되고나서 Tistory

반응형

댓글