PS

[C++] 9663 : N-Queen

왕방토 2021. 2. 6. 00:11
728x90

골드 Ⅴ

 

#include <iostream>
#include <cstdlib>

using namespace std;

int n;
int cnt = 0;
int map_c[15];

int promising(int cidx) {

	for (int i = 0; i < cidx; i++) {
		if (map_c[i] == map_c[cidx] || (cidx - i) == abs(map_c[i] - map_c[cidx]))
			return 0;
	}
	
	return 1;
}

void nqueen(int cidx) {

	if (cidx == n) {
		cnt++;
		return;
	}

	for (int ridx = 0; ridx < n; ridx++) {
		map_c[cidx] = ridx;
		if (promising(cidx)) nqueen(cidx + 1);
	}
}

int main() {
	scanf("%d", &n);
	nqueen(0);
	printf("%d", cnt);
}

 

백트래킹 문제!

드디어 알고리즘 하나 더 하려고 발을 딛었다.. 맨날 DFS만 주구장창 풀었는데ㅋㅋ..

 

주의깊게 봐야할 점

이차원 배열을 사용하지 않고 일차원 배열로 이차원 배열을 나타냄

백트래킹의 "다시 뒤로 돌아가는" 부분은 for문 + 재귀 함수를 이용함으로써 자동적으로 해결 됨

③ cidx를 n까지 봐줌 -> 실제 체스판에서는 n+1 번째 항까지 봐주는 것 -> n번째 항도 똑같이 백트래킹 해주기 위함이다

dy/dx == m 이고, 체스판에서 대각선에 위치한 것은 m = ±1 인 것이므로 dy/dx = ±1, 즉 dy = abs(dx) 해주면 된다

 

 

이차원 배열을 사용하지 않고 일차원 배열로 이차원 배열을 나타냄

 

예를들어, n=4일 때

map_c[0] = 1, map_c[1] = 3, map_c[2] = 0, map_c[3] = 2

로 나타내어 주면

(r, c) -> (0, 1), (1, 3), (2, 0), (3, 2) 로 나타내어 준 것과 같다!!

배열의 인덱스를 활용하여

배열의 차수 줄여주기!(2차원 -> 1차원)

응용하면 n차원 -> n-1차원 으로도 쓸 수 있지 않을까?

아무튼 배열의 인덱스는 여기저기 쓸 데가 많다

 

백트래킹의 "다시 뒤로 돌아가는" 부분은 for문 + 재귀 함수를 이용함으로써 자동적으로 해결 됨

 

예를들어 nqueen 의 이 for문에서, ridx = 2 라고 해보자

for (int ridx = 0; ridx < n; ridx++) {
	map_c[cidx] = ridx;
	if (promising(cidx)) nqueen(cidx + 1);
}

promising(cidx) (map_c 의 cidx에 ridx를 넣은 것이 타당한가? 를 확인하는 함수) 를 거치고

nqueen(cidx + 1) 을 하다보면, 언젠가 promising 결과값이 0이 되든 cidx가 n까지 가든 해서 ridx = 2일 때 if 문이 끝날 것이다

그럼 자동으로 ridx = 3 로 넘어가므로 백트래킹을 해주는 셈이 된다!

 

 

추가로

이건 내가 이해한건데.. 백트래킹은 브루트포스 -> 근데 가지치기(볼 필요 없는 애들은 안 봄)가 추가 된 인 것 같다

 

이걸 생각하면 ②의 이해가 더 쉽게 되는 것 같다

 

그럼 앞으로도 백트래킹 문제를 훨씬 많이 풀어보길 바라며..