hdu1116回溯N皇后问题

题目连接

经过思考,不难发现:恰好N个皇后放在不同行不同列,那么是不是可以转换成N个皇后所在行分别确定(一人一行)的情况下对她们的所在列的枚举。

也就是列的全排列生成问题,我们用c[x]表示x行皇后的列编号。而我们知道0~N-1的排列一共有N的阶乘,枚举量不会超过它。

if(cur==n)//递归边界。只要走到这里,所有的皇后必然不冲突
    tot++;

根据我们的代码,我们是从cur=0开始的,

 #include<iostream>
#include<cstdio>
using namespace std;
int n,tot,c[];
void search(int cur)
{
int i,j;
if(cur==n)//递归边界。只要走到这里,所有的皇后必然不冲突
tot++;
else
for(i=;i<n;i++)
{
int ok=;
c[cur]=i;//尝试把第cur行的皇后放在第i列
for(j=;j<cur;j++)
if(c[cur]==c[j]||cur-c[cur]==j-c[j]||cur+c[cur]==j+c[j])//检查是否与前面的皇后冲突
{
ok=;break;
}
if(ok)
search(cur+);//如果合法,继续递归
}
}
int main()
{
int a[];
for(int i=;i<;i++){
tot=;
n=i+;
search();
a[n]=tot;
}
while(cin>>n&&n)
{
cout<<a[n]<<endl;
}
}

search(cur+1);//如果合法,继续递归       并不会判断n+1行的皇后。所以我们从cur=0开始。

当然从cur=1开始也是可以的,但此时

if(cur==n+1)//递归边界。只要走到这里,所有的皇后必然不冲突

tot++;

程序中的

if(c[cur]==c[j]||cur-c[cur]==j-c[j]||cur+c[cur]==j+c[j])//检查是否与前面的皇后冲突
        {
            ok=0;break;
        }

既然是逐行放置,那么皇后肯定不会横向攻击,因此只需检查是否纵向和斜向攻击即可。条件c[cur]==c[j]||cur-c[cur]==j-c[j]||cur+c[cur]==j+c[j])

y-x标示了主对角线,斜率为1;

y+x标示了副对角线,斜率为-1;

画画图就知道了

我们还可以用二维数组vis[2][]直接判断当前尝试放的皇后的对角线和纵向有没有皇后已经放了,注意主对角线标示y-x可能为负数,所以要加n

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,tot,c[];
int vis[][];
void search(int cur)
{
if(cur==n)tot++;
else{
for(int i=;i<n;i++){
if(!vis[][i]&&!vis[][cur+i]&&!vis[][cur-i+n]){
c[cur]=i;//如果不需要打印皇后所在列,可以舍去
vis[][i]=vis[][cur+i]=vis[][cur-i+n]=;//标示这些空已经不能再放皇后
search(cur+);
vis[][i]=vis[][cur+i]=vis[][cur-i+n]=;//回溯要改回来
}
}
}
}
int main()
{
int a[];
for(int i=;i<;i++){
memset(vis,,sizeof(vis));
tot=;
n=i+;
search();
a[n]=tot;
}
while(cin>>n&&n)
{
cout<<a[n]<<endl;
}
}
上一篇:Sharpdevelop使用StyleCop


下一篇:清北学堂 清北-Day1-R1-Count