八皇后问题是一个以国际象棋为背景的问题:如何能够在
8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。当且仅当 n = 1 或 n ≥ 4 时问题有解。
因此只需要判断放下的当前位置的棋子的位置是否被之前放下的棋子位置有冲突即可。可以使用普通的二维数组的判读,但是这样写起来很麻烦,有冗余。
此题
可以借助两个二维数组图来帮助理解,分别建立两个x,y-x 的二维数组和x,x+y的二维数组来进行理解。cur-c[cur]==j-c[j] || cur+c[cur]==j+c[j] 用来判断皇后(cur,c[cur])和(j,c[j])是否在同一条对角线上。使用c[cur]==c[j]判断是否在同一列上。
代码为:
#include<iostream>
#include<string.h>
#include<cstdio>
using namespace std;
int n,tot;
int c[50];
void dfs(int cur)
{
if(cur==n)
tot++;
else for(int i=0;i<n;i++)
{
c[cur]=i; //把第cur行的皇后放在第i列
int ok=1;
//检查是否和前面的皇后冲突
for(int j=0;j<cur;j++)
{
if(c[cur]==c[j]||cur-c[cur]==j-c[j]||cur+c[cur]==j+c[j])
{
ok=0;
break;
}
}
if(ok)
dfs(cur+1);
}
}
int main()
{
while(cin>>n&&n)
{
memset(c,0,sizeof(c));
tot=0;
dfs(0);
cout<<tot<<endl;
}
}
结点数很难进一步减少,但程序效率可以继续提高:利用二维数组vis[2][]直接判断当前尝试的皇后所在的列和两个对角线是否有其他皇后。注意对角线标y-x可能为负,存取时要加上n。
因此代码可以改为:
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
int n,c[50],tot,vis[3][50];
void search(int cur)
{
if(cur==n)
tot++;
else for(int i=0;i<n;i++)
{
//利用二维数组直接判断
if(!vis[0][i]&&!vis[1][cur-i+n]&&!vis[2][cur+i])
{
c[cur]=i; //用来打印,如果不用打印结果,可以删除
vis[0][i]=vis[1][cur-i+n]=vis[2][cur+i]=1;
search(cur+1);
vis[0][i]=vis[1][cur-i+n]=vis[2][cur+i]=0;
}
}
}
int main()
{
while(cin>>n&&n)
{
tot=0;
memset(vis,0,sizeof(vis));
search(0);
cout<<tot<<endl;
}
}