N皇后
8皇后问题是在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
现在请你求在n*n的棋盘上摆放n个皇后的方案数。
输入格式
一行,一个正整数n ( n < 13)
输出格式
一行,一个整数,表示所求的方案数
输入样例
8
输出样例
92
我们先看八皇后问题
在8×8的棋盘上,放置8个皇后(棋子),使两两之间互不攻击。所谓互不攻击是说任何两个皇后都要满足:
(1)不在棋盘的同一行;
(2)不在棋盘的同一列;
(3)不在棋盘的同一对角线上。
因此可以推论出,棋盘共有8行,每行有且仅有一个皇后,故至多有8个皇后。这8个皇后每个应该放在哪一列上是解该题的任务。
- 解题思路一 —— 回溯法**
1、定义Try( i )——试探放第 i 行上的皇后。
2、讨论将第 i 行上的皇后放在 j 列位置上的安全性。
我们可以逐行地放每一个皇后,因此,在做这一步时,假定第 i 行上还没有皇后,不会在行上遭到其它皇后的攻击。只考虑来自列和对角线的攻击。我们定义 q( i ) = j 表示第 i 行上的皇后放在第 j 列,一旦这样做了,就要考虑第 i 个皇后所在的列不安全了,这时让 C[ j ]= 0,同时,要考虑通过( i, j ) 位置的两条对角线也不安全了。分析看出从左上到右下的对角线上的每个位置都有 i – j = 常数 的特点;从左下到右上的对角线上的每个位置都有 i + j = 常数 的特点。比如两条对角线上的点,一条有 i - j = -1,一条有 i + j = 7 的特点。
定义 int R[ 17 ]
R[ k ] k= 2,3,…,16
k = i + j
i = 1,2,…,8 j = 1,2,…,8
描述从右上至左下的对角线是否安全
数据类型为整型
1--------安全
0-------不安全
最优解:
#include <stdio.h>
#include <math.h>
void nqueen(int n);
int n;//皇后个数
int count=0;
int line[30]={0},right[40]={0},left[40]={0};
int main()
{
scanf("%d",&n);
nqueen(0);
printf("%d",count);
return 0;
}
void nqueen(int k){//k行
int i=0;
if(k==n){
count++;
}
for(i=0;i<n;i++){//i列
if(line[i]
//该列不安全
||left[k+i]
//右上到左下这条线不安全
||right[i-k+n])
//左上到右下这条线不安全
continue;
else{
line[i]=1;
left[i+k]=1;
right[i-k+n]=1;
//置为不安全
nqueen(k+1);
line[i]=0;
left[i+k]=0;
right[i-k+n]=0;
//回溯时置为安全
}
}
}
- 解题思路二 ——扫描法
#include <stdio.h>
#include <math.h>
void nqueen(int n);
int n;//皇后个数
int queenpos[20];//第i行皇后所在的列
int count=0;
int main()
{
scanf("%d",&n);
nqueen(0);
printf("%d",count);
return 0;
}
void nqueen(int k){
int i=0;
if(k==n){
count++;
}
for(i=0;i<n;i++){
int j;
for(j=0;j<k;j++){
if(queenpos[j]==i||(queenpos[j]-j)==(i-k)||(queenpos[j]+j)==(i+k))
break;
}
if(j==k){
queenpos[k]=i;
nqueen(k+1);
}
}
}