八皇后也是个经典算法题目了。 早有耳闻,不曾亲见。
在国际象棋中,皇后可以在棋盘上攻击横竖斜八个方向上的敌人(这也太diao了叭),所以就想想出一种算法,能让这八个皇后同时安置在棋盘上,皇后之间不能有冲突。挺有意思的(呵,实际上就是宫斗好吧。。。)
题目来自洛谷试炼场深度优先搜索——八皇后https://www.luogu.org/problemnew/show/P1219
题目描述
这只是跳棋放置的一个解。请编一个程序找出所有跳棋放置的解。并把它们以上面的序列方法输出。解按字典顺序排列。请输出前3个解。最后一行是解的总个数。
输入格式:
一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的。
输出格式:
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入样例:
6
输出样例:
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
刚拿到这道题目,我大脑中的暴力因子就异常活跃——用一个二维数组来存下整个棋盘的状态,然后开始逐行深度优先搜索。
这道题我是用到了搜索与回溯,这里先上一个超暴力下的超时算法(\流汗)。
超时算法
int sum=0;
int map[100][100], ans[100];
//位置检查
bool CheckPos(int x, int y, int n){
for(int i=1; i<=n; i++){
if(map[i][y]==1)
return false;
for(int j=1; j<=n; j++)
if(abs(i-x)==abs(j-y) && map[i][j]==1)
return false;
}
return true;
}
void Queen(int row, int n){
if(row>n){
sum++;
if(sum<=3){
for(int i=1; i<=n; i++)
cout<<ans[i]<<" ";
cout<<endl;
}
return ;
}
for(int col=1; col<=n; col++){
if(CheckPos(row, col, n)){
map[row][col]=1; //放入皇后
ans[row]=col;
Queen(row+1, n); //搜索下一列
map[row][col]=0; //复原回溯
}
}
}
上面这种算法的结果在预料之中,最后两个样例2/8,87分TLE掉了,毕竟这个做法暴力上又加暴力结果肯定是超时,太暴力了!
开始探索其他的有效算法吧,仔细想想,我非要把整个棋盘全存下来吗?只要用一个一维数组存下每一行皇后所在的列号,同时用辅助数组标识出该皇后所占领的列号和对角线不就行了。
算法思路清晰,其实和上面那个超时算法大致相同,都是搜索与回溯,话不多说这就开始实现。
升级版!
//DFS八皇后
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int sum=0;
//依次是行 —列 —双对角线
int a[100], b[100], c[100], d[100];
//dfs与回溯
void Queen(int i, int n){
if(i>n){
sum++;
if(sum<=3){ //前三行
for(int k=1; k<=n; k++)
cout<<a[k]<<" ";
cout<<endl;
}
return;
}
else{
for(int j=1; j<=n; j++){
if(!b[j] && !c[i+j] && !d[i-j+n]){ //其他皇后没有占领
a[i]=j; //i行j列安置皇后
b[j]=1; //纵列占领
c[i+j]=1; d[i-j+n]=1; //对角线占领
Queen(i+1, n); //dfs
b[j]=0;
c[i+j]=0;
d[i-j+n]=0;
//复原回溯
}
}//for
}
}
int main()
{
int n;
cin>>n;
Queen(1, n);
cout<<sum;
return 0;
}
到此结束问题解决,原来这就是有名的八皇后啊(呵, 宫斗)。
我对深搜的粗略理解
就是沿着可行路径逐步向下搜索,如果有一天发现走到了一个无路可去的死胡同,就跳出当前操作回到了上一步,探索其他可行路径。就是这样一点一点的探索,直到到达了终点或者搜索了所有可行路径,才结束搜索操作