DOTY
19) 백준 9663 - N-Queen 본문
728x90
반응형
9663번: N-Queen
N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다. N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.
www.acmicpc.net
몇 주 전에 하려다가 머리가 안 굴러가서 포기했던 문제.
#include <iostream>
using namespace std;
int N;
int answer;
int check(int chess[15][15], int x, int y) {
int tmp_X = x-1;
int min = y-x;
int sum = x+y;
while(tmp_X >= 0) {
if(min + tmp_X >= 0) {
if(chess[tmp_X][min + tmp_X] == 1) return 0;
}
if(sum - tmp_X < N) {
if(chess[tmp_X][sum - tmp_X] == 1) return 0;
}
if(chess[tmp_X][y] == 1) return 0;
tmp_X--;
}
return 1;
}
void bf(int cnt, int chess[15][15], int x) {
if(cnt == N) {
answer++;
return;
}
for(int j = 0; j < N; j++) {
int ck = check(chess, x, j);
if(check(chess, x, j) == 1) {
chess[x][j] = 1;
bf(cnt+1, chess, x+1);
chess[x][j] = 0;
}
}
}
int main(void) {
int chess[15][15] = {0, };
answer = 0;
cin >> N;
int cnt = 0;
bf(cnt, chess, 0);
cout << answer << endl;
}
2차 배열을 사용했다. 쉬운 듯 어려웠던 문제.
백트래킹 문제로 Queen을 그냥 하나하나 옮겨가면서 놓으면서 체크하면 끝난다.
처음 check 함수에서 놓는 체스말 아래 행까지 체크하려고 하고, bf 함수에서 for문을 행과 열 전부 돌아가며 체크하려고 했는데 시간초과가 걸렸다.
여기서 아이디어는
1. 한 행에 놓으면 그 행은 더 이상 놓지 못한다. 다르게 생각하면 N×N 보드판에 N개의 Queen체스 말을 놓기 위해선 한 행에 하나씩 모든 행에 각각 하나씩 놓아야 한다.
2. 체스판 위쪽부터 체스말을 놓으므로 새로 놓는 행을 포함하여 그 아래 행은 체크할 필요가 전혀 없다.
sum 은 행과 열의 합, min은 행과 열의 차 이 둘을 이용해서 대각선을 계산해 줬는데 이 방법을 사용해서 굳이 2차로 안 하고 1차 배열을 사용해서도 문제를 풀 수 있었다.
< 초반 오답 코드 >
#include <iostream>
using namespace std;
int N;
int answer;
int check(int chess[15][15], int x, int y) {
int tmp_X = x;
int tmp_Y = y;
while(tmp_X >= 0 && tmp_Y >= 0) {
if(chess[tmp_X][tmp_Y] == 1) {
return 0;
}
else {
tmp_X--;
tmp_Y--;
}
}
tmp_X = x;
tmp_Y = y;
while(tmp_X < N && tmp_Y < N) {
if(chess[tmp_X][tmp_Y] == 1) {
return 0;
}
else {
tmp_X++;
tmp_Y++;
}
}
tmp_X = x;
tmp_Y = y;
while(tmp_X < N && tmp_Y >= 0) {
if(chess[tmp_X][tmp_Y] == 1) {
return 0;
}
else {
tmp_X++;
tmp_Y--;
}
}
tmp_X = x;
tmp_Y = y;
while(tmp_X >= 0 && tmp_Y < N) {
if(chess[tmp_X][tmp_Y] == 1) {
return 0;
}
else {
tmp_X--;
tmp_Y++;
}
}
for(int i = 0; i < N; i++) {
if(chess[i][y] == 1) {
return 0;
}
}
return 1;
}
void bf(int cnt, int chess[15][15], int x) {
if(cnt == N) {
answer++;
return;
}
for(int i = x; i < N; i++) {
for(int j = 0; j < N; j++) {
int ck = check(chess, i, j);
if(check(chess, i, j) == 1) {
chess[i][j] = 1;
bf(cnt+1, chess, i+1);
chess[i][j] = 0;
}
}
}
}
int main(void) {
int chess[15][15] = {0, };
answer = 0;
cin >> N;
int cnt = 0;
bf(cnt, chess, 0);
cout << answer << endl;
}
확실히 초반에 비해서 시간이 반으로 줄고 이중 for문을 사용하지 않다 보니 훨씬 시간이 줄어든 것이 보였다.
check안의 함수는 억지로 꾸역꾸역 줄이려다 보니 저렇게 간단해지긴 했는데 sum, min을 따로 안 하고 오답 코드처럼 보기 쉽게 해도 통과된다
728x90
반응형
'Algorithm > BFS&DFS' 카테고리의 다른 글
21) 백준 2151 - 거울 설치 (0) | 2023.05.26 |
---|---|
20) 백준 2206 - 벽 부수고 이동하기 (0) | 2023.05.02 |
18) 백준 1707 - 이분 그래프 (0) | 2023.04.13 |
17) 백준 2665 - 미로만들기 (0) | 2023.04.12 |
16) 백준 1520 - 내리막 길 (0) | 2023.04.05 |
Comments