본문 바로가기
알고리즘&자료구조/재귀

백준 1780

by dongR 2024. 2. 27.

문제분석

 

종이 크기는 1(3의 0승), 3(3의 1승), 9(3의 2승)... 형태로 주어짐 

각각 1*1, 3*3, 9*9 크기로 이루어짐

 

k=1 일 때 종이를 자를 수 없음 (1을 3으로 나누면 몫이 0)

k=3 일때 종이를 한 번 자를 수 있음 (3을 3으로 나누면 몫이 1, 즉 1*1 9개로 나눠짐)

k=3의 n승일때 n번 종이를 자를 수 있음 

 

1. 함수식 

func(n, x, y)

n : 종이 크기 

x : 모든 종이가 똑같은 값인지 검사할 행

y : 모든 종이가 똑같은 값인지 검사할 열

 

func(3, 0, 0)으로 예시를 들어보면 

(0,0) 값을 기준으로 삼고 3*3 모든 종이의 칸과 비교 

종이의 각 칸이 모두 같은 수로 되어있다면 해당 수의 개수 1 증가 후 재귀함수 종료

 

종이의 각 칸이 모두 같은 수로 되어있지 않다면 종이 크기를 3으로 나눠서 감소 

만약 종이의 크기가 1이라면 3으로 나누면 몫이 0이기 때문에 더 이상 나눌 수 없으므로 재귀함수 종료

func(3/3, 0, 0) -> func(1, 0, 0) -> func(1/3, 0, 0) X

 

2. Base condition 

종이의 크기를 3으로 나누었을때 몫이 0인 경우 재귀함수 종료, 종이의 크기가 1인 경우에 해당됨

 

 

코드

#include<iostream>	
using namespace std;

// 종이의 각 칸
int board[2188][2188];

// -1[0], 0[1], 1[2] 채워진 종이 개수
int cnt[3];

void func(int n, int x, int y) {

	// 종이의 각 칸이 모두 같은 수로 되어있는지 체크 
	bool sameValCk = true;
	for (int i = x; i < n + x; i++) {
		for (int j = y; j < n + y; j++) {
			if (board[x][y] != board[i][j]) {
				sameValCk = false;
				break;
			}
		}
		if (!sameValCk) break;
	}

	if (sameValCk) {
		cnt[board[x][y] + 1] += 1;
		return;
	}
	else {
		int z = n / 3;
		// 1*1은 한칸이기 때문에 무조건 똑같은 수로 이루어져 있어서 조건을 체크할 필요 없음
		// 9등분에 대해서 재귀함수 실행 
		// 다른 값이랑 비교할 좌표를 각 9등분한 시작위치로 세팅하기 위해서는 x축, y축 방향으로 이동시 z를 더해줘야됨
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {				
				func(z, x + i*z, y + j*z);
			}
		}
	}

}

int main(void) {
	ios_base::sync_with_stdio(0);
	cin.tie(0);

	// 1.입력
	int N;
	cin >> N; // 3의 n승 형태

	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cin >> board[i][j];
		}
	}

	// 2.로직
	func(N, 0, 0);

	// 3.출력
	cout << cnt[0] << '\n' << cnt[1] << '\n' << cnt[2];

	return 0;
}

 

int z = n / 3;
// 1*1은 한칸이기 때문에 무조건 똑같은 수로 이루어져 있어서 조건을 체크할 필요 없음
// 9등분에 대해서 재귀함수 실행 
// 다른 값이랑 비교할 좌표를 각 9등분한 시작위치로 세팅하기 위해서는 x축, y축 방향으로 이동시 z를 더해줘야됨
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {				
        func(z, x + i*z, y + j*z);
    }
}

 

9*9 행렬을 9등분을 하게 되면 3*3 행렬 9개로 분할되는데 모든 3*3 행렬의 시작위치가 다르기 때문에 z만큼의 값을 곱해줘야 한다. x와 y를 더해주는 이유는 9등분을 한 지점에서 다시 종이의 개수를 계산하기 때문인데 x와 y를 더해주지 않으면 무조건 (0,0)의 위치부터 시작하기 때문이다.

이해하기 어렵다면 9*9 행렬을 9 등분하고 (0,3) 위치에 있는 3*3 행렬을 다시 9 등분하는 과정을 살펴보면 확인할 수 있다.

 

 

특이사항

무조건 재귀함수로만 구현해야 된다고 생각해서 반복문을 쓰지 않아야 된다고 생각을 했었는데 반복문 따로 재귀함수 따로 사용해야 되는 부분이 다른 경우도 있기 때문에 적절히 섞어서 쓰면 된다.

'알고리즘&자료구조 > 재귀' 카테고리의 다른 글

백준 1992  (0) 2024.03.01
백준 2630  (0) 2024.02.29
백준 17478  (0) 2024.02.26
백준 1074  (0) 2024.02.26
백준 하노이의 탑(11729)  (0) 2024.02.22