N皇后问题
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 20132 Accepted Submission(s): 9089
你的任务是,对于给定的N,求出有多少种合法的放置方法。
解题思路:
首先要回求解n皇后问题,其次就是题目有一个小陷阱,输入的n只是从1~10,但是后面的测试数据,会反复测1~10这些数,则如果输入一个n就求一次解,那么最终会导致超时,因此想将1~10皇后问题的解都制表,然后根据输入的n进行快速访问就可以了。
求解n皇后问题主要用的是回溯的思想,在放的时候要注意判断,一个皇后的同行同列以及斜线上都不能有其他的皇后,因此如果递归到某一位置发现它不能放置皇后,那么就要进行回溯。以四皇后为例。
如图为程序开始,先确定列再确定行,先从第一列开始,发现第一行经过判断后可以放皇后则放置第一个皇后,放置完此皇后后,则图中红线所画过的方格不能再放置皇后了,第一列已经放过皇后了,就要考虑第二列,然后从第一行开始考虑,发现第一行不能放,第二行不能放,直到第三行,发现可以放置皇后,则放置皇后,放置完后如下图所示:
第二个皇后放置完后,同样的先将不能再放置皇后的空格标记,即图中红线所划过的空格,此时开始搜索第三列,发现第一行不能放皇后,第二行也不能放皇后,第三行不能放置皇后,第四行也不能放置皇后,则发现第三列的任一行都不能放置皇后,此时就要进行回溯了,则2列3行不放置皇后(因为这种方法没有解),则我会恢复成第一个图片的状态。此时回溯回来后,就要考虑第2列第4行是否能放置皇后,从图1可以看出,是可以的,则在第2列第4行放置皇后,如下图:
在2列4行放置完皇后后如图红色线所划过的空格都不能再放皇后了,此时考虑在第三列放置皇后。发现从第1行开始考虑,到第2行发现了一个能放皇后的位置,就在第3列第2行放置皇后,然后再次更新不能放置皇后的格子,更新后的状态如下图所示:
此时递归更深一层要在第4列放置皇后,经过考虑后,第4列1~4行都不能放置皇后,则要回溯,将3列2行的格子不放置皇后,考虑3~4这些位置,发现也不能放置皇后,再次回溯,将2列4行的位置恢复,此时第二列也考虑完了,再次回溯,将1行1列的位置恢复,考虑在2~4行放置皇后,则
发现可以在第2行放置皇后。经过一系列回溯之后,放置皇后的状态如下所示:
同样的开始考虑在第二列可以安放皇后的位置放置皇后,大概思路就是这样,能走下去就进行深一层的递归,不能走下去就进行回溯。
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
int n; //问题规模
int ans; //解的个数
int vis[12][12]; //标记数组
int row[12],col[12]; //标记行,标记列
int table[12];
bool check(int i,int j) {
int s,t;
if(row[i]) return false; //这一行已有皇后,该位置不合法。
if(col[j]) return false; //这一列已有皇后,该位置不合法。
//判断(i,j)的斜线是否有皇后。
//判断左上角有没有皇后。
for(s=i-1,t=j-1;s>=0&&t>=0;s--,t--) {
if(vis[s][t]) return false;
}
//判断右下角有没有皇后。
for(s=i+1,t=j+1;s<n&&t<n;s++,t++) {
if(vis[s][t]) return false;
}
//判断左下角有没有皇后
for(s=i+1,t=j-1;s<n&&t>=0;s++,t--) {
if(vis[s][t]) return false;
}
//判断右下角有没有皇后
for(s=i-1,t=j+1;s>=0&&t<n;s--,t++) {
if(vis[s][t]) return false;
}
return true;
}
void dfs(int j) {
if(j == n) {
ans++;
return;
}
for(int i = 0; i < n; i++) {
bool flag = check(i,j); //检测i行j列是否可以放皇后
if(flag) {
vis[i][j] = 1; //在i行j列放置皇后
row[i] = 1;
col[j] = 1;
dfs(j+1); //考虑在下一列放皇后
vis[i][j] = 0;
row[i] = 0;
col[j] = 0;
}
}
}
int main() {
for(int i = 1; i <= 10; i++) {
memset(vis,0,sizeof(vis));
memset(row,0,sizeof(row));
memset(col,0,sizeof(col));
n = i;
ans = 0;
dfs(0);
table[i] = ans;
}
while(~scanf("%d",&n)) {
if(n == 0) break;
printf("%d\n",table[n]);
}
return 0;
}