您的位置:首页 > 其它

DFS入门篇---八皇后!

2017-05-19 09:41 183 查看
让我们试着解决一些更有技巧的回溯问题。

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。


很快能想到如下思路:

1,逐行放置皇后,检查并保证不与已经放置的皇后冲突,并记录在数组中。

2,如果某一行无解了,返回上一行(回溯)。

3,填完了最后一行,记解的个数+1,同时输出数组中保存的解。

朴素的实现上述思路容易超时,下面引入一些小技巧

技巧:

1,如果不需要保存具体的解而只要计数,可不用数组进行解的记录。

2,把棋盘沿主对角线,副对角线,列分别编号,这样在做标记的时候可以在O(1)时间完成。

#include<bits/stdc++.h>
using namespace std;

bool v[3][256];

typedef pair<int,int> P;
vector<P> a; //用来保存解,但实际上只用保存纵坐标...这里用pair多此一举
int n,sum=0;
bool t=1; //表示是否输出了3个

inline bool judge(int i,int j) {
if(!v[0][j]&&!v[1][j-i+n]&&!v[2][i+j])
return 1;
return 0;
}
//逐行放置皇后
bool dfs(int i) {
if(i==n) {
sum++;
if(sum<=3) {
for(int j=0; j<a.size(); j++) {
printf("%d ",a[j].second+1);
}
putchar('\n');
} else t=0;
return 0;
}
//开始对这一行进行尝试
bool pre=0;
for(int j=0; j<n; j++) {
if(judge(i,j)==1) {
pre=1;
if(t) a.push_back(P(i,j));
v[0][j]=1; //列
v[1][j-i+n]=1; //主对角线
v[2][i+j]=1; //副对角线
if(dfs(i+1)==0) {
if(t) a.pop_back();
v[0][j]=0;
v[1][j-i+n]=0;
v[2][i+j]=0; //如果下一步dfs无解,证明这一步填错,退回
pre=0;
}
}
}
return pre;
}

int main() {
scanf("%d",&n);
dfs(0);
printf("%d",sum);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dfs 搜索 递归算法