https://www.acmicpc.net/problem/2630
문제
> 아래 <그림 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과 각 정사각형칸의 색(하얀색 또는 파란색)이 주어질 때 잘라진 하얀색 색종이와 파란색 색종이의 개수를 구하는 프로그램을 작성하시오.

접근
많은 색종이중 첫번째 0,0번째꺼를 기준으로 잡고 이중반복으로 돌며 기준과 다른 색인 색종이가 나오면 반복문을 바로 종료하고 문제에 주어진대로 가로세로 이등분 총 4등분을 내준다.
4등 분을 내줄 때, 각각의 종이에 대해 시작점과 크기를 인자로 넘겨준다.
이중 반복문을 통해 i와 j가 각각 0부터 2까지로 해서 나눈다.
각각 종이는 시작점이 0,0 0,1 1,0, 1,1 인데
이 좌표는 몇 번째 조각인지에 대한 인덱스이므로 이를 첫 색종이에서 몇번 째 위치의 조각인지로 바꿔줘야한다.
따라서 크기가 처음에 8이었다면 8,0,0에서 시작하고 쪼개지면 각각 (4,0x4+0,0x4+0), (4,0x4+0,1x4+0), (4,1x4+0,0x4+0), (4,1x4+0,1x4+0)이된다.
즉 각각의 좌표는 ixsize/2+인자로 들어온 row, jxsize/2+ 인자로 들어온 col이다.
결론적으로 전체적 흐름은 색종이의 첫좌표를 기준으로 잡아 모든 조각과 비교해 다른게 있으면 바로 반복을 종료하고 나와 4등분 내주고 만약 다른게 없어 끝까지 비교가 끝난다면 첫 좌표의 색을 인덱스로 한 결과 벡터에 색별로 1씩 누적해 전체 조각수를 계산한다.
문제해결
> 색종이의 색을 저장할 이차원 벡터 paper와 두 색의 종이 수를 누적할 rst벡터를선언해주고 이를 처리할 Paper메소드를 정의한다.
> 인자로 색종이의 크기, 시작행, 시작열을 받고 이를기반으로 첫 종이를 tmp에 저장한다.
> 종이를 이중 반복으로 돌며 tmp와 비교하는데 다른 종이가 있으면 break로 깨고 나온다. 다른색이 있냐 없냐를 저장할 valid 부울 변수에 다른종이가 있으면 true가 들어가고 없으면 false그대로 들어있다.
> valid값에 따라 false(다른색이 없다)면 tmp의 색을 인덱스로 한 rst벡터(tmp는 0이나 1이다)에 1씩 누적한다. 최종 종이의 수가 담긴다.
> valid가 true면 종이를 4등분 해줘야 하므로 i와 j를 2까지 해서 단위를 잡고 ij를 기반으로 처음에 인자로 들어온 row,col을 이용해 새로운 조각의 좌표를 잡아 재귀해준다.
코드
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
int N;
vector<vector<int>> paper;
vector<int> rst;
void Paper(int size, int row, int col)
{
int tmp = paper[row][col];
bool valid = false;
for (int i = row; i < row + size; i++)
{
for (int j = col; j < col + size; j++)
{
if (paper[i][j] != tmp)
{
valid = true;
break;
}
}
if (valid) break;
}
if (!valid)
{
rst[tmp] += 1;
return;
}
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
Paper(size / 2, i * (size / 2) + row, j * (size / 2) + col);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> N;
rst.resize(2);
paper.assign(N, vector<int>(N, 0));
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++) cin >> paper[i][j];
}
Paper(N, 0, 0);
for (auto& a : rst) cout << a << '\n';
}

후기
색종이 나누는 문제를 몇번 해봐서 그런지 어렵지 않았다.