백준 1780번 (종이의 개수, C++, DivideAndConquer) [BAEKJOON]

종이의 개수

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

시간 제한메모리 제한제출정답맞힌 사람정답 비율
2 초256 MB35301209691572058.541%

문제

N×N크기의 행렬로 표현되는 종이가 있다.

종이의 각 칸에는 -1, 0, 1 중 하나가 저장되어 있다.

우리는 이 행렬을 다음과 같은 규칙에 따라 적절한 크기로 자르려고 한다.

1. 만약 종이가 모두 같은 수로 되어 있다면 이 종이를 그대로 사용한다.

2. (1)이 아닌 경우에는 종이를 같은 크기의 종이 9개로 자르고, 각각의 잘린 종이에 대해서 (1)의 과정을 반복한다.

이와 같이 종이를 잘랐을 때, -1로만 채워진 종이의 개수, 0으로만 채워진 종이의 개수,

1로만 채워진 종이의 개수를 구해내는 프로그램을 작성하시오.

입력

첫째 줄에 N(1 ≤ N ≤ 37, N은 3k 꼴)이 주어진다.

다음 N개의 줄에는 N개의 정수로 행렬이 주어진다.

출력

첫째 줄에 -1로만 채워진 종이의 개수를, 둘째 줄에 0으로만 채워진 종이의 개수를,

셋째 줄에 1로만 채워진 종이의 개수를 출력한다.

예제 입력 1

9
0 0 0 1 1 1 -1 -1 -1
0 0 0 1 1 1 -1 -1 -1
0 0 0 1 1 1 -1 -1 -1
1 1 1 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
0 1 -1 0 1 -1 0 1 -1
0 -1 1 0 1 -1 0 1 -1
0 1 -1 1 0 -1 0 1 -1

예제 출력 1

10
12
11

출처

알고리즘 분류


분할정복 문제

종이가 모두 같다면 카운트

아니면 9부분으로 나눈 후에 다시 확인

길이가 1 (3^0)이 될때 까지 해당 로직을 반복한다.

통과된 코드

#include <iostream>
#include <cmath>

using namespace std;

constexpr int MAX = 2187;

int map[MAX][MAX];

int N;

// 0 = 0 / 1 = 1 / -1 = 2
int result[3];

void ConquestDivison(int x, int y, int w)
{
	// 종이의 길이가 1(3^0) 이라면 해당 종이의 카운트를 증가시켜 줍니다.
	if (w == 0) { 
		if (map[x][y] == -1) result[2]++;
		else result[map[x][y]]++;
		return;
	}

	int number = map[x][y];
	int temp = pow(3, w);
	bool check = true;
	for (int i = 0; i < temp; i++) {
		for (int j = 0; j < temp; j++) {
			// 모든 부분이 서로 같은지 체크합니다.
			// 다르다면 빠져나가고 마킹해줍니다.
			if (number == map[x + i][y + j]) { continue; }
			else {
				check = false;
				break;
			}
		}
		if (!check) break;
	}

	if (check) { // 모든 부분이 같다면 해강 종이의 카운트를 올려줍니다.
		if (number == -1) result[2]++;
		else result[map[x][y]]++;
		return;
	}
	
	int temp2 = pow(3, w - 1);

	// 분할 정복 9등분
	ConquestDivison(x              , y              , w - 1);
	ConquestDivison(x              , y + temp2      , w - 1);
	ConquestDivison(x              , y + 2 * (temp2), w - 1);

	ConquestDivison(x + temp2	   , y				, w - 1);
	ConquestDivison(x + temp2	   , y + temp2		, w - 1);
	ConquestDivison(x + temp2	   , y + 2 * (temp2), w - 1);

	ConquestDivison(x + 2 * (temp2), y	            , w - 1);
	ConquestDivison(x + 2 * (temp2), y + temp2	    , w - 1);
	ConquestDivison(x + 2 * (temp2), y + 2 * (temp2), w - 1);
}


int main()
{
	ios_base::sync_with_stdio(false); // scanf와 동기화를 비활성화
	// cin.tie(null); 코드는 cin과 cout의 묶음을 풀어줍니다.
	cin.tie(NULL);
	cout.tie(NULL);

	cin >> N;

	// 문제를 입력받습니다.
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cin >> map[i][j];
		}
	}

	// N이 3의 몇승인지 확인합니다.
	int k = 0;
	int temp = N;
	while (temp != 1) {
		temp /= 3;
		k++;
	}
	
	ConquestDivison(0, 0, k);

	cout << result[2] << "\n" << result[0] << "\n" << result[1];

	return 0;
}

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤