문제풀이
[문제풀이]백준 9633번: N-Queen
khoneybee
2023. 1. 19. 17:19
●해설
백트래킹을 사용하여 해결해야 하는 대표적인 문제이다.
먼저 퀸이 같은 행 또는 열에 있으면 안되기 때문에 한 열당 하나의 퀸을 둔다는 것을 전제로 시작한다.
2차원 배열을 쓸 필요 없이 1차원 배열을 사용하여 배열의 index(i)를 열(raw)로, 배열의 값(arr[i])을 행(column)으로 잡는다.
int n;
int arr[MAX]; //arr[i]: column, i: row, arr[0]은 편의를 위해 쓰지 않음.
int cnt = 0; //경우의 수
다음으로 퀸을 둘 자리가 다른 퀸의 공격범위에 있는지 체크를 해야한다.
같은 행에 있는 경우에는 간단하게 판별이 가능하다. 하지만 대각선에 있는 경우는 처음 보면 헷갈릴 수 있으니
잘 보고 이해해보자.
먼저 판별할 퀸의 좌표를(a, b)라고 하겠다. 그러면 좌표(a, b)의 대각선에 위치한 모든 좌표 (x, y)는
abs(x - a) == abs(y - b)를 만족한다(abs()는 절댓값). 아래 그림을 보고 잘 생각해보자.
(대각선에 있는 모든 좌표에서 퀸의 좌표를 뺀 후 절댓값을 씌우면 위의 식을 만족한다.)
다음으로 판별식을 코드로 확인해 보겠다.
bool check(int v) { //1 ~ v - 1열에 있는 퀸의 공격범위에 있는지 체크
for (int i = 1; i < v; i++) {
if ( v - i == abs(arr[v] - arr[i]) || v == i || arr[i] == arr[v]) {
return false;
}
}
return true;
}
열 v - 1까지의 모든 퀸의 좌표를 확인하기 위해 for문 사용하고, 각각의 열에 있는 퀸과 v에 놓일 퀸을 비교하여
놓을 수 없으면 false를 반환하도록 만들었다.
자 이제 판별식도 만들었으니 전체 코드를 확인해보자.
#include <iostream>
#define MAX 15
using namespace std;
int n;
int arr[MAX]; //arr[i]: column, i: row, arr[0]은 쓰지 않음(편의를 위해)
int cnt = 0; //경우의 수
bool check(int v) { //1 ~ v - 1열에 있는 퀸의 공격범위에 있는지 체크
for (int i = 1; i < v; i++) {
if ( v - i == abs(arr[v] - arr[i]) || v == i || arr[i] == arr[v]) {
return false;
}
}
return true;
}
void BT(int v) {
if (v == n + 1) { //n만큼의 퀸을 둔 것을 확인 했으니 cnt++
cnt++;
return;
}
for (int i = 1; i <= n; i++) { //1행부터 n행까지 차례대로 둠.
arr[v] = i; //올려두고
if (check(v)) {
BT(v + 1); //가능하면 다음 열의 퀸으로 이동
}
}
}
int main()
{
cin >> n;
BT(1);//1열부터 시작
cout << cnt;
return 0;
}
매개변수로 열의 index를 의미하는 v를 받고 for문으로 1부터 n행 까지 올려둘 수 있는지 판단한다.
둘 수 있으면 다음 열로 이동 후 이 과정을 v가 n과 같아졌을 때까지 반복 후 n + 1을 만나게 되면 경우의 수를 1 올려주고
return한다.