GitHubSeob

C++ / 백준 / 1780 / 종이의 개수 본문

Baekjoon/Silver

C++ / 백준 / 1780 / 종이의 개수

GitHubSeob 2021. 8. 24.

문제

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

 

1780번: 종이의 개수

N×N크기의 행렬로 표현되는 종이가 있다. 종이의 각 칸에는 -1, 0, 1의 세 값 중 하나가 저장되어 있다. 우리는 이 행렬을 적절한 크기로 자르려고 하는데, 이때 다음의 규칙에 따라 자르려고 한다.

www.acmicpc.net

문제풀이

첫 줄부터 끝줄까지 최솟값과 최댓값을 구한다.

이전 최솟값, 이전 최댓값 변수를 만들어 이전에 돌린 max, min값들을 저장한다.

이전 최솟값, 이전 최댓값, 현재 최솟값, 최댓값이 다르면 종이를 9 분할한다.

다 같아 반복문을 다 돌면 해당 종이에 적힌 값의 개수를 1 늘린다.

 

		int prev_y = y;
		int prev_x = x;
		int max_value = 0;
		int min_value = 0;
		for (y; y < prev_y + size; ++y) {
			int prev_min = min_value;
			int prev_max = max_value;
			max_value = *max_element(paper[y].begin() + x, paper[y].begin() + x + size);
			min_value = *min_element(paper[y].begin() + x, paper[y].begin() + x + size);

			if (y != prev_y && (max_value != min_value || max_value != prev_max || min_value != prev_min)) {
				Divide(prev_y, prev_x, size / 3);
				Divide(prev_y + size / 3, prev_x, size / 3);
				Divide(prev_y + 2 * size / 3, prev_x, size / 3);

				Divide(prev_y, prev_x + size / 3, size / 3);
				Divide(prev_y + size / 3, prev_x + size / 3, size / 3);
				Divide(prev_y + 2 * size / 3, prev_x + size / 3, size / 3);

				Divide(prev_y, prev_x + 2 * size / 3, size / 3);
				Divide(prev_y + size / 3, prev_x + 2 * size / 3, size / 3);
				Divide(prev_y + 2 * size / 3, prev_x + 2 * size / 3, size / 3);
				break;
			}
		}

 

 

처음 for문을 돌릴 때는 이전 값이 존재할 수 없으므로 y!=prev_y (이때는 prev_y=y이다)가 아니고, 이전 최솟값, 이전 최댓값, 최솟값, 최댓값 중 하나라도 다른 값이 있으면 분할하는 코드.

y: 0 ~ 1/3 , 1/3 ~ 2/3, 2/3 ~ 3/3

x: 0 ~ 1/3 , 1/3 ~ 2/3, 2/3 ~ 3/3

해서 총 9 부분으로 나눈다.

한 번이라도 분할했으면 또 분할하면 안 되므로 breakm를 걸어 반복문을 종료한다.

 

		if (y == prev_y + size)
			cnt[paper[prev_y][prev_x] + 1]++;

cnt [0] = -1의 개수, cnt [1] = 0의 개수, cnt [2] = 1의 개수로 두었으므로 종이에 적힌 값 +1에 해당하는 곳의 값을 +1 한다.

 

	if (size == 1)
		cnt[paper[y][x] + 1]++;

3x3 배열을 9 분할하면 1칸짜리가 총 9개 생긴다. 더 분할할 수 없으므로 이 칸에 적힌 값 개수만큼 cnt배열 값을 늘려준다.

 

 

 

 

코드

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<vector<int>>paper;
vector<int>cnt(3, 0);

void Divide(int y, int x,int size) {
	if (size == 1)
		cnt[paper[y][x] + 1]++;
	else {
		int prev_y = y;
		int prev_x = x;
		int max_value = 0;
		int min_value = 0;
		for (y; y < prev_y + size; ++y) {
			int prev_min = min_value;
			int prev_max = max_value;
			max_value = *max_element(paper[y].begin() + x, paper[y].begin() + x + size);
			min_value = *min_element(paper[y].begin() + x, paper[y].begin() + x + size);

			if (y != prev_y && (max_value != min_value || max_value != prev_max || min_value != prev_min)) {
				Divide(prev_y, prev_x, size / 3);
				Divide(prev_y + size / 3, prev_x, size / 3);
				Divide(prev_y + 2 * size / 3, prev_x, size / 3);

				Divide(prev_y, prev_x + size / 3, size / 3);
				Divide(prev_y + size / 3, prev_x + size / 3, size / 3);
				Divide(prev_y + 2 * size / 3, prev_x + size / 3, size / 3);

				Divide(prev_y, prev_x + 2 * size / 3, size / 3);
				Divide(prev_y + size / 3, prev_x + 2 * size / 3, size / 3);
				Divide(prev_y + 2 * size / 3, prev_x + 2 * size / 3, size / 3);
				break;
			}
		}
		if (y == prev_y + size)
			cnt[paper[prev_y][prev_x] + 1]++;
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	int N;
	cin >> N;
	paper = vector<vector<int>>(N, vector<int>(N, 0));
	int y = 0, x = 0;

	for (y = 0; y < N; ++y)
		for (x = 0; x < N; ++x)
			cin >> paper[y][x];

	Divide(0, 0, N);
	for (int idx = 0; idx < 3; idx++)
		cout << cnt[idx] << "\n";
}

 

'Baekjoon > Silver' 카테고리의 다른 글

C++ / 백준 / 18870 / 좌표 압축  (0) 2021.08.31
C++ / 백준 / 1992 / 쿼드트리  (0) 2021.08.25
C++ / 백준 / 11728 / 배열 합치기  (0) 2021.08.24
C++ / 백준 / 2022 / 사다리  (0) 2021.08.20
C++ / 백준 / 2512 / 예산  (0) 2021.08.20