N皇后问题## 标题
一:题目介绍
八皇后问题是一个古老而著名的问题,是回溯算法的经典问题。该问题是十九世纪著名的数学家高斯在1850年提出的:在8*8的国际象棋棋盘上,安放8个皇后,要求没有一个皇后能够“吃掉”任何其它一个皇后,即任意两个皇后不能处于同一行,同一列或者同一条对角线上,求解有多少种摆法。
高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法得到结论,有92种摆法。
本实验拓展了N皇后问题,即皇后个数由用户输入。
八皇后在棋盘上分布的各种可能的格局数目非常大,约等于2的32次方种,但是,可以将一些明显不满足问题要求的格局排除掉。由于任意两个皇后不能同行,即每行只能放置一个皇后,因此将第i个皇后放在第i行上,这样在放置第i个皇后时,只要考虑它与前i-i个皇后处于不同列和不同对角线位置上即可。
二:算法思想
解决这个问题需要采用回溯法,首先将第一个皇后放置在第一行第一列,然后,依次在下一行放置一个皇后,直到八个皇后全部放置安全。在放置每个皇后时,都依次对每一列进行检测,首先,检测放在第一列是否已经放置皇后,如不冲突,则将皇后放置在该列,否则,选择该行的下一列进行检测。如该行的八列都冲突,则返回到上一行,重新选择位置,依次类推。
特殊想法;
(1)要素一:解空间
一般想法:利用二维数组,用【i】【j】确定一个皇后的位置!
优化:利用约束条件,只需要一维数组即可!
x:array[1…n] of integer;
x[i]:i表示第i行皇后
x[i]表示第i行上皇后放在第几列
这么说好理解一点
第一行x[0]=1;放在第一列
第二行x[1]=3;放在第三列
第三行x[2]=4;放在第四列
第五行x[3]=2;放在第二列
这样有些讨巧。还是决定不用了。
(2)要素二:约束条件
一维数组的情况:
首先不同行:x[i]中的i不能出现两次;
不同列l;x[i]的值能出现两次;
不同对角线:abs[x[i]-x[j]]==abs[i-j];
二维数组的情况:
首先不同行:x[i][j]中的i 不能出现两次;
不同列 :x[i][j]中的j 不能出现两次;
不同对角线:abs[i-i]==abs[j-j]
(3)状态树
将搜索过程中的每个状态用树的形式表示出来!
画出状态数对书写程序有很大的帮助!
(4)回溯
最终要的就是要有回溯思想,否则你是不是皇后就死了,就跟我们下象棋的时候的悔棋是一样的。
程序的结束条件:一组解:设标志,找到一解后更改标志,以标志作为结束循环的条件,所有解:K=0;
判断约束函数判断第k个后能不能放在x[k]处两个皇后不能放在统一斜线上:
若2个皇后放置的位置分别是(i,j)和(k,l),且i-j=k-1或i+j=k+1,则说明这2个皇后处于同一斜线上。
第二天想到的思想:我们可以先确定皇后在第几行然后在确定皇后在第几列的问题。也就是在dfs中的for语句和if语句。
三:算法实现
#include<iostream>
#include<cmath>
using namespace std;
int n;
int x[100]={0};
int cnt = 0;
int output()
{
cout << "第"<< cnt<<"种放置方法为:"<<endl;
for(int i=1;i<=n;i++)
{
cout<<"("<<i<<","<<x[i]<<")"<<endl;
}
}
bool place(int k)
{
for(int j=1;j<k;j++)
if(x[j]==x[k]||abs(j-k)==abs(x[j]-x[k]))
{
return 0;
}
else
{
return 1;
}
}
int dfs(int t,int n)
{
if(t>n)
{
cnt++;
output();
}
else
{
for(int i=1;i<n;i++)
{
x[t]=i;
if(place(t)==1)
{
dfs(t+1,n);
}
}
}
}
int main()
{
cin >> n;
cout << n << "皇后的放置方法为"<<endl;
dfs(1,n);
return 0;
}