백준 1992: 쿼드 트리/재귀함수

Jimin·2022년 7월 20일
0

알고리즘

목록 보기
19/71

문제

흑백 영상을 압축하여 표현하는 데이터 구조로 쿼드 트리(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의 숫자로 이루어져 있으며, 영상의 각 점들을 나타낸다.


출력

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



#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>
#include <string>
using namespace std;
const int MAX = 65;
int N;
int vid[MAX][MAX];
int isAll(int start, int end, int size);
void compress(int start, int end, int size);

int main() {
    cin >> N;
    string s;
    for (int i = 0; i < N; i++) {
        cin >> s;
        for (int j = 0; j < N; j++) {
            vid[i][j] = s[j] - '0';
        }
    }

    compress(0, 0, N);

    return 0;
}



void compress(int x, int y, int size) {
    int a = isAll(x, y, size);
    //printf("isAll: %d\n", a);
    if (a == 0) {
        cout << 0;
        return;
    }
    if (a == 1) {
        cout << 1;
        return;
    }
    cout << '(';
    compress(x, y, size/2);
    compress(x + size/2, y, size/2);
    compress(x, y +size/2, size/2);
    compress(x + size/2, y+size/2, size/2);
    cout << ')';

}

int isAll(int y, int x, int size) {
    bool isAllOne = true; 
    bool isAllZero = true;
    for (int i = x; i < x+size; i++) {
        for (int j = y; j < y+size; j++) {
            if (vid[i][j] == 1) isAllZero = false;
            if (vid[i][j] == 0)isAllOne = false;
        }
    }
    if (isAllZero)return 0;
    else if (isAllOne)return 1;
    else return 2;
}

솔직히 나는 문제 이해부터 어려워서 우선 구글링을 통해 문제 이해부터 했다.

https://yabmoons.tistory.com/450

[ 백준 1992 ] 쿼드트리 (C++)
백준의 쿼드트리(1992) 문제이다. [ 문제풀이 ] 먼저 문제에서 설명으로 나와있는 이상한 그림과 이상한 맵에서 왜 답이 그렇게 나오는지 한번 알아보고 넘어가자. . 이 그림에 대한 정답으로 "(0(0011)(0(0111)01..

yabmoons.tistory.com



처음 사이즈의 좌표가 모두 0이거나 1이 아닌 경우, 4등분을 하고

그 각각의 4등분된 좌표에서 다시 모두 0이거나 1인지 확인하는 과정을 반복하는 것이 압축의 과정이며,

시계방향대로 네 등분한 좌표를 1, 2, 3, 4번째 좌표라고 할 때,

우선 첫번째 사진에서 첫 번째 좌표는 모두 0이므로 그냥 0이되고

두 번째 좌표에서는 모두 동일하지 않으므로 다시한 번 네 등분이 되고 (0011)이 된다.

세 번째 좌표에서는 다시 한번 좌표가 나뉘고, (0(0111)01)이 된다.

마지막 좌표는 그냥 1이다.

최종적으로 (0(0011)(0(0111)01)1) 이라는 답이 나오게 된다.

코드를 치면서 많이 헤맸는데, 우선적으로 중요한 건 좌표를 확실히 하는 것인 것 같다.

나는 보통 x, y라고 배열에 그대로 넣지만 사실 좌표와 배열에서 나타내는 순서는 반대이다.

평소 배열에서 쓰는 i, j는 좌표로 치환하면 (j, i)가 된다.

그것을 항상 유의하며 써 주어야하며,

함수를 두 개 만들어 줬는데 여기서 배열을 전역으로 선언했으므로 함수 파라미터에 넣어줄 필요는 없다.

isAll함수는 맨왼쪽 오른쪽 좌표(x, y)와 현재 좌표의 크기를 넣어주어 현재 좌표가 모두 0, 1 인지 확인해주는 코드를 만들어 줬다.

compress함수에서는 또한 맨왼쪽 오른쪽 좌표(x, y)와 현재 좌표의 크기를 넣어주었고,

isAll 함수를 이용해서 모두 0이라고 나오면 0을, 1이라고 나오면 1을 출력하고 return을 통해 종료해준다.

그 밖의 경우, 4등분을 나눈뒤 각각의 맨왼쪽 오른쪽 좌표(x, y)와 현재 좌표를 다시 compress에 넣어준다.

괄호 같은 경우, compress를 다시 시작할 때와 끝날 때 넣어주면 된다.

profile
https://github.com/Dingadung

0개의 댓글