문제:

아래 <그림 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로 주어지며, 각 숫자 사이에는 빈칸이 하나씩 있다.

출력:

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

풀이방법:

반복해서 반으로 나누고 조건을 파악하는 대표적인 분할 정복문제다.

0,0부터 시작해서 check라는 함수를 통해서 이 색종이가 '흰색', '검은색', '나눠야함' 인지 확인한다. 확인하는 방법은 왼쪽 위의 색깔을 기준으로 삼고, 색종이의 크기만큼 반복문을 통해서 모두 같은 색깔인지 체크한다.

이렇게 white나 black이 나온다면 갯수를 더해주고 종료를 하고, 만약 나눠야 한다면 4개 사각형으로 나눠서 다시 한번 check하는 과정을 거치도록 한다.

반복문을 사용하면서 색깔을 확인하는 방식이기때문에 알아서 더 이상 나눌 수 없다면 종료하게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
white, black = 00
 
def check(x,y,n):
    color = paper[x][y]
    div = False
    for i in range(n):
        for j in range(n):
            if color !=paper[x+i][y+j]:
                div = True
                break
    if div:
        return "div"
    else:
        if color == 0:
            return "white"
        else:
            return "black"
                
def divide(x,y,n):
    global white,black
    color = check(x,y,n)
    if color == 'white':
        white+=1
    elif color == 'black':
        black+=1
    else:
        divide(x,y,n//2)
        divide(x+n//2,y,n//2)
        divide(x,y+n//2,n//2)
        divide(x+n//2,y+n//2,n//2)
 
= int(input())
paper = []
for i in range(n):
    paper.append(list(map(int,input().split())))
 
divide(0,0,n)
print(white)
print(black)
cs

문제링크:

www.acmicpc.net/problem/2630

 

2630번: 색종이 만들기

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

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2583. 영역 구하기  (0) 2021.05.18
[BOJ]3055. 탈출  (0) 2021.05.11
[BOJ]3273. 두 수의 합  (0) 2021.04.27
[BOJ]9184. 신나는 함수 실행  (0) 2021.04.22
[BOJ]2981. 검문  (0) 2021.04.20

문제:

흑백 영상을 압축하여 표현하는 데이터 구조로 쿼드 트리(Quad Tree)라는 방법이 있다. 흰 점을 나타내는 0과 검은 점을 나타내는 1로만 이루어진 영상(2차원 배열)에서 같은 숫자의 점들이 한 곳에 많이 몰려있으면, 쿼드 트리에서는 이를 압축하여 간단히 표현할 수 있다.

주어진 영상이 모두 0으로만 되어 있으면 압축 결과는 "0"이 되고, 모두 1로만 되어 있으면 압축 결과는 "1"이 된다. 만약 0과 1이 섞여 있으면 전체를 한 번에 나타내지를 못하고, 왼쪽 위, 오른쪽 위, 왼쪽 아래, 오른쪽 아래, 이렇게 4개의 영상으로 나누어 압축하게 되며, 이 4개의 영역을 압축한 결과를 차례대로 괄호 안에 묶어서 표현한다.

위 그림에서 왼쪽의 영상은 오른쪽의 배열과 같이 숫자로 주어지며, 이 영상을 쿼드 트리 구조를 이용하여 압축하면 "(0(0011)(0(0111)01)1)"로 표현된다.  N ×N 크기의 영상이 주어질 때, 이 영상을 압축한 결과를 출력하는 프로그램을 작성하시오.

입력:

첫째 줄에는 영상의 크기를 나타내는 숫자 N 이 주어진다. N 은 언제나 2의 제곱수로 주어지며, 1≤N ≤64의 범위를 가진다. 두 번째 줄부터는 길이 N 의 문자열이 N 개 들어온다. 각 문자열은 0 또는 1의 숫자로 이루어져 있으며, 영상의 각 점들을 나타낸다.

출력:

영상을 압축한 결과를 출력한다.

풀이방법:

 분할정복을 사용해서 풀어야 하는 문제다. 반복해서 영상을 4분할로 나누면서, 같은 숫자로 구성되어 있는지 파악하면 된다.

 각 분할된 분면에서 왼쪽 상단에 있는 점을 기준점으로 삼아서, 반복문을 순회하면서 같은 숫자로 구성되어 있는지 확인한다.

 만약 같은 숫자로 구성되어 있으면 더 이상 분할할 필요가 없으니 현재 기준점을 출력하도록 한다. 하지만 같은 숫자로 구성되어 있지 않다면 재귀적으로 지금 영상을 4분할로 나눠서 위의 작업을 반복해주면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
= int(input())
numbers=[]
for _ in range(N):
    numbers.append(list(map(int,list(input()))))
 
def quadTree(N,x,y):
    curr = numbers[x][y]
    divide = False
    for i in range(x,x+N):
        for j in range(y,y+N):
            if numbers[i][j]!=curr:
                divide=True
    if divide:
        print("(",end="")
        quadTree(N//2,x,y) # leftupper
        quadTree(N//2,x,y+N//2# rightupper
        quadTree(N//2,x+N//2,y) # leftunder
        quadTree(N//2,x+N//2,y+N//2# rightunder
        print(")",end="")
    else:
        print(curr,end="")
quadTree(N,0,0)
cs

문제링크:

www.acmicpc.net/problem/1992

 

1992번: 쿼드트리

첫째 줄에는 영상의 크기를 나타내는 숫자 N 이 주어진다. N 은 언제나 2의 제곱수로 주어지며, 1≤N ≤64의 범위를 가진다. 두 번째 줄부터는 길이 N 의 문자열이 N 개 들어온다. 각 문자열은 0 또는

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]1707. 이분 그래프  (0) 2020.11.24
[BOJ]7562. 나이트의 이동  (0) 2020.11.19
[BOJ]1041. 주사위  (0) 2020.11.12
[BOJ]1059. 수2  (0) 2020.11.10
[BOJ]10775. 공항  (0) 2020.10.29

문제:

크기가 N*N인 행렬 A가 주어진다. 이때, A의 B제곱을 구하는 프로그램을 작성하시오. 수가 매우 커질 수 있으니, A^B의 각 원소를 1,000으로 나눈 나머지를 출력한다.

입력:

첫째 줄에 행렬의 크기 N과 B가 주어진다. (2<=N<=5, 1<=B<=100,000,000,000)

둘째 줄부터 N개의 줄에 행렬의 각 원소가 주어진다. 행렬의 각 원소는 1,000보다 작거나 같은 자연수 또는 0이다.

출력:

첫째 줄부터 N개의 줄에 걸쳐 행렬 A를 B제곱한 결과를 출력한다.

풀이방법:

B의 최대 크기가 100,000,000,000인 만큼 효율적인 계산 방법이 필요한 문제다. 따라서 다음과 같은 규칙에 의해서 계산을 한다.

 

A^N일 때,

if N이 짝수라면, (A^2)^(N/2)로 수정한다.

if N이 홀수라면, (A^(N-1))*A로 수정하고, A는 answer에 곱한다.

N이 1이 될 때까지 위를 반복하고, 1이면 그 때의 A를 answer에 곱한다.

 

위와 같이 계산을 한다면 지수가 log2단위로 줄어들기 때문에 최대 100,000,000,000번 연산이 최대 36번으로 줄어들게 될 것이다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
n,b = map(int,input().split())
 
def matmul(A,B):
    result = [[0]*len(A) for _ in range(len(B))]
    for i in range(len(A)):
        for j in range(len(B)):
            for k in range(len(A[0])):
                result[i][j] += A[i][k]*B[k][j]
                result[i][j] %= 1000
    return result
            
matrix = []
for _ in range(n):
    matrix.append(list(map(int,input().split())))
    
answer = [[1 if i==else 0 for i in range(n)] for j in range(n)]
 
while b !=1:
    temp = matrix[:]
    if b%2:
        answer = matmul(answer,temp)
        b-=1
    else:
        matrix = matmul(temp,temp)
        b//=2
 
answer = matmul(answer,matrix)
for ans in answer:
    print(*ans)
cs

문제링크:

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

'Algorithm > Python' 카테고리의 다른 글

[BOJ]5052. 전화번호 목록  (0) 2020.06.23
[BOJ]12865. 평범한 배낭  (0) 2020.06.18
[BOJ]1837. 암호제작  (0) 2020.06.11
[BOJ]9506. 약수들의 합  (0) 2020.06.09
[Programmers]2018 Kakao[1차]추석 트래픽  (0) 2020.05.26

+ Recent posts