关于八皇后问题有很多种解法,今天只写一种利用全排列的解法,其他的一些解法看情况在整理补充。
全排列算法https://blog.csdn.net/qq_41706331/article/details/86521823
题目描述:
在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
结题思路:
对于这个问题如果采用组合数的的方式来枚举每一种情况,那么将需要次枚举,效率太低。
但换个思路,考虑到每行只能放置一个皇后,每列也只能放置一个皇后,如果把n列皇后所在的行号依次写出来那么就是1~8的一个
排列。因此只要枚举1~8的所有排列,统计其中合法的方案即可,只有n!个排列,比之前的枚举优秀很多。
#include<cstdio>
#include<cmath>
int n;
int count=0;
int QueenList[10];
bool StatusTable[10]={0};
void NQueen(int index)
{
if(index==n+1)
{
bool flag=true;
int i,j;
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
if(abs(i-j)==abs(QueenList[i]-QueenList[j]))
flag=false;
}
if(flag)
count++;
return;
}
int x;
for(x=1;x<=n;x++)
{
if(StatusTable[x]==false)
{
QueenList[index]=x;
StatusTable[x]=true;
NQueen(index+1);
StatusTable[x]=false;
}
}
}
int main()
{
// printf("有几个皇后?");
// scanf("%d",&n);
// NQueen(1);
// printf("%d个皇后共有%d种合法方案\n",n,count);//我靠为什么这个编译器打印汉字是问号???
printf("how many Queens?\t");
scanf("%d",&n);
NQueen(1);
printf("there are %d schemes of %d Queens.\n",count,n);
return 0;
}
事实上,当已经放置了一部分皇后时,可能剩余的皇后无论怎样放置都不可能合法,这时就没必要往下递归了,直接返回上层即可。
利用回溯法优化刚刚的算法
void NQueen(int index)
{
if(index==n+1)
{
count++;
return;
}
int x,i;
for(x=1;x<=n;x++)
{
if(StatusTable[x]==false)//如果第x行没有皇后
{
bool flag=true; //flag为true表示在index位放入皇后无冲突,为false表示有冲突
for(i=1;i<index;i++)//遍历之前的皇后
{
// if(abs(x-i)==abs(QueenList[x]-QueenList[i])) 此时x还未放入index位 ,所以不能这么写
if(abs(index-i)==abs(x-QueenList[i]))//如果在index为放入x与之前某个皇后冲突 ,直接跳出循环,进入下一次外循环,将下一个x测试
{
flag=false;
break;
}
}
if(flag==true)
{
QueenList[index]=x;
StatusTable[x]=true;
NQueen(index+1);
StatusTable[x]=false;
}
}
}
}