쿼드트리
문제
흑백 영상을 압축하여 표현하는 데이터 구조로 쿼드 트리(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의 숫자로 이루어져 있으며, 영상의 각 점들을 나타낸다.
출력
영상을 압축한 결과를 출력한다.
예제 입력 1
8
11110000
11110000
00011100
00011100
11110000
11110000
11110011
11110011
예제 출력 1
((110(0101))(0010)1(0001))
🚩 분할정복(Divide and Conquer)
분할정복은 크고 방대한 문제를 조금씩 나눠가면서 용이하게 풀 수 있는 문제의 단위로 나눈 다음, 그것들을 다시 합쳐서 해결하는 개념으로 구성된 알고리즘이다.
대표적으로는 퀵소트나 병합정렬이 있다.
알고리즘 풀이방식은 재귀적으로 자신을 호출하면서 연산의 단위를 조금씩 줄어나가는 프로세스이다.
쿼드트리 문제는 주어진 N x N 의 점들을 4분의 1씩 쪼개며 하나의 정사각형이 온전히 흰 점(0)과 검은 점(1)으로 구성되는 경우를 찾아야 하는 문제이다.
https://www.acmicpc.net/problem/2630
2630번: 색종이 만들기
첫째 줄에는 전체 종이의 한 변의 길이 N이 주어져 있다. N은 2, 4, 8, 16, 32, 64, 128 중 하나이다. 색종이의 각 가로줄의 정사각형칸들의 색이 윗줄부터 차례로 둘째 줄부터 마지막 줄까지 주어진다.
www.acmicpc.net
색종이 만들기 문제도 쿼드트리와 동일하게 정사각형을 4분할하며 하나의 사각형 요소가 모두 같은 요소인지를 검사하면 된다.
사실 쿼드트리도 완전 똑같은 개념인데 문제가 처음에 잘 이해가 안가서.. 이해하는데 시간이 걸렸다;
백준의 색종이 만들기 문제는 13분만에 풀었는데.. 쿼드트리 문제는 괄호를 열고 닫기에서 헷갈려서 거의 50분이나 걸렸다..!
#include <iostream>
#include <string>
using namespace std;
int N;
char arr[65][65];
void CheckQuadTree(int length, int x, int y)
{
char dot = arr[x][y];
for(int i = x; i < x+length; i++)
{
for(int j = y; j < y+length; j++)
{
if(arr[i][j] != dot)
{
cout << "(";
CheckQuadTree(length / 2, x, y);
CheckQuadTree(length / 2, x, y+ length / 2);
CheckQuadTree(length / 2, x+ length / 2, y);
CheckQuadTree(length / 2, x+ length / 2, y+ length / 2);
cout << ")";
return;
}
}
}
cout << to_string(dot);
}
int main()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> N;
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
char c;
cin >> c;
arr[i][j] = c - '0';
}
}
CheckQuadTree(N, 0, 0);
return 0;
}
먼저, 입력 값이 줄줄이 붙은 숫자로 입력되기 때문에 char 형 배열에 저장하여 한글자 한글자를 분리해 저장하였다.
이후, (0,0) 원소부터 배열내용을 비교해가며 첫번째 원소 dot = arr[x][y]; 의 값과 배열안에 있는 값이 다른 경우, 해당 사각형 공간이 하나의 원소로 이루어진게 아니기 때문에 재귀함수를 호출하여 다시 4분할 검사를 수행했다.
이때, 처음에 나는 괄호 "(" 와 ")" 닫기를 재귀함수 안에서 처리하려 했지만, 재귀적으로 쌓아진 여러 개의 괄호들("((" 라거나 ")))" 같은)을 추후에 처리하는게 너무 어려워서 어떻게 풀이해야하나 계속 고민했다.
정답은 그냥 재귀함수를 호출하는 위치 앞뒤로 바로바로 cout << "(";를 출력하면 되는거였다..
너무 복잡하게 재귀함수의 매개변수로 모든걸 넘겨줄 필요는 없다는 사실을 다시 한번 깨달았다.
https://www.acmicpc.net/problem/1992
1992번: 쿼드트리
첫째 줄에는 영상의 크기를 나타내는 숫자 N 이 주어진다. N 은 언제나 2의 제곱수로 주어지며, 1 ≤ N ≤ 64의 범위를 가진다. 두 번째 줄부터는 길이 N의 문자열이 N개 들어온다. 각 문자열은 0 또
www.acmicpc.net
'💻코딩테스트 > 백준' 카테고리의 다른 글
[백준/C++] 1932번 : 정수 삼각형 (DP 연습) (0) | 2023.07.13 |
---|---|
[백준/C++] 2580번 : 스도쿠 (백트래킹 연습) (0) | 2023.07.11 |
[백준/C++] 18870번 : 좌표 압축 (vector - unique, erase, lower_bound) (0) | 2023.07.04 |
[백준/C++] 10815번 : 숫자 카드 (binary_search) (0) | 2023.07.04 |
[백준/C++] 10814번 : 나이순 정렬 (stable_sort) (0) | 2023.06.30 |