对于这个八皇后问题,两个月前把我难为的,如今复习到数据结构树这一章,我又见到了这个所谓的八皇后问题,决定要把它解决掉!
在国际象棋棋盘上(8*8)放置八个皇后,使得任意两个皇后之间不能在同一行,同一列,也不能位于同于对角线上。问共有多少种不同的方法,并且指出各种不同的放法。
【算法思路】
第一步:不考虑约束条件,每个皇后放法都有八种方式去放,也就构成了一个完整八叉树。
第二步:对这个八叉树进行遍历,对不符合要求的树进行截枝,留下来的就是可行的方案。
最重要的地方:解空间的构建,这个八皇后问题可以用一个一维数组,x[i],来表示,i表示第几行,x[i]表示第几位置。于是我们考虑第一个条件,不能再同一行,同一列于是我们得到x[i]不能相同。剩下一个条件是不能位于对角线上,这个条件不是很明显,我们经过分析得到,设两个不同的皇后分别在j,k行上,x[j],x[k]分别表示在j,k行的那一列上。那么不在同一对角线的条件可以写为abs((j-k))!=abs(x[j]-x[k]),其中abs为求绝对值的函数。
递归方式:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
static int num;
static int *x;
static int sum;
bool place(int k)
{
for(int j = 1;j<k;j++)
if(abs(x[k] - x[j]) == abs(k-j)||x[j] == x[k])
return false;
return true;
}
void backtrack(int t)
{
if(t>num) //num为皇后的数目
{
sum++;//sum为所有的可行的解
for(int m = 1;m<num;m++)
{
cout<<x[m];//这一行用输出当递归到叶节点的时候,一个可行解
}
cout<<endl;
}
else
for(int i = 1;i<=num;i++)
{
x[t] = i;
if(place(t)) backtrack(t+1);//此处的place函数用来进行我们上面所说的条件的判断,如果成立,进入下一级递归
}
}
int main()
{
num = 8;
sum = 0;
x = new int[num+1];
for(int i= 0;i<=num;i++)
x[i] = 0;
backtrack(1);
cout<<"方案共有"<<sum;
}
解题法二:
#include <iostream>
using namespace std;
static int tot=0;
void search_q(int cur,int* p,int n)
{
int i,j;
if(cur==n)
{
tot++;
cout<<tot<<":";
for(i=0;i<n;i++)
cout<<p[i];
cout<<endl;
}
else for(i=0;i<n;i++)
{
int ok=1;
p[cur]=i;
for(j=0;j<cur;j++)
{
if(p[cur]==p[j]||p[cur]+cur==p[j]+j||p[cur]-cur==p[j]-j)
{
ok=0;
break;
}
}
if(ok) search_q(cur+1,p,n);
}
}
int main()
{
int arr[8][8];
int c[8];
search_q(0,c,8);
return 0;
}