题目-八 / n皇后C++解-深搜
八皇后与n皇后问题的C++解
前言
回溯法也称试探法,用于寻找一个问题的可行解。该方法首先暂时泛起问题规模大小的闲置,从最小规模开始将问题的候选解按某种顺序逐一枚举和检验,选择一个可行的候选解,然后扩大规模,继续试探。打到要求的规模时,所有的候选解就形成了问题的可行解。8皇后和n皇后的问题就是基于回溯法解决的。
< 八皇后问题 >
题目要求:在一个8*8的棋盘上放置 8 个皇后,使8个皇后中没有两个或两个以上的皇后会出现在同一行、同一列、或同一对角线上。
一、解决思路:
1.先简单表示出我们想要的伪代码。
queen_all (k) //k是这次放置皇后的所在列,如果k=1,那就是第一列。
{
for (i=1;i<=8;++i) //i是行,先从第一行开始试探
if (如果把皇后放在 k 列 i 行 是可行的){
在该列第 i 行放入皇后
if (k==8) 输出解
else queen_all(k+1) //继续排列下一行
}
}
2.针对这个伪代码,我们要解决如下问题:
- 如何判断是否在 k 列 i 行可行?
- 放下一个皇后后,怎么让其所在行,列,两条斜线都不能再次放置另一个皇后?
- 如果某一列的每一行都无法再次放置皇后,要怎么回溯到上一次?
- 如果k==8时,输出一个可行解后怎么在查找下一个可行解?
- -最后我们要怎么退出?
A. 对于①、②问题,我们先要找到一种方式来储存可行解,当然我们也可以用二维数组来模拟棋盘,每放置一个皇后就把这位置标记下来,并把所在行列斜线都标记为false,再进行下一次放置皇后时,根据该行该列是否是 false 来放置。但自习思考这样会造成标记和输出上的麻烦。为了使问题便于思考和简化代码,我们可以采取以下方法。
- 用一维数组 col[9] 来表示每列上皇放置的位置,如row[A]=B:代表第 A 列第9行放置了一个皇后。
- 用 bool row[9],digLeft[16],digRight [16]分别表示每行,左低右高线和右低左高线上是否被禁止放置皇后。如row[A]=false,digLeft[B]=false,digRight[C]=false,表示第 A 行,第B条左低斜线和第C条右高斜线上不能放置皇后。至于列就不用了管它了。通过规律我们可以把 B 和 C 用 k 和 i 表示出来。
B. 对于③,但循环 i=9 时自然会退出回溯到上一次放置皇后,不过我们要额外加一条代码来取消上一次的标记。对于④也是同理。
C. 当我们把所有能够试探的方法试探玩后,k=9,自然就会退出递归。
一切都思考清楚后就可以释放代码了,好耶!
二、代码实现
void queen_all(int k) //开始传递数字'1',数组开全局
{
int i=0;
for (i=1;i<=8;++i)
{
if (row[i]!=1&&digLeft[k+i-1]!=1&&digRight[8+k-i]!=1) //之前偷懒把数组全初始化为 0 ,所以用1来代替false。
{
col[k]=i;
row[i]=digLeft[k+i-1]=digRight[8+k-i]=1; //标记
if (k==8)
{
for (int j=1;j<=8;++j)
cout<<col[j]<<' ';//输出解,如“8 4 1 3 6 2 7 5”代表第一列第八行,第二列第四行......第八列第五行
cout<<endl;
}
else queen_all(k+1); //跳转到下一行
row[i]=digLeft[k+i-1]=digRight[8+k-i]=0; //清除标记
}
}
}
总之还是挺容易的。除了我这个憨憨之前想用二维数组强解
< n皇后问题 >
简单,吧8换成n的事,函数多传递个n就好==
顺带一提如果按照行输出(以上是按照列输出的),则结果会一样= =。
上完整版代码
#include<iostream>
using namespace std;
void queen_all(int k,int n);
int col[100]={0},times=0; //用times来记录一共多少种结果
bool row[100]={0},digLeft[100]={0},digRight[100]={0};
int main()
{
int n=0;
cin>>n;
queen_all(1,n);
cout<<times;
return 0;
}
void queen_all(int k,int n)
{
int i=0;
for (i=1;i<=n;++i)
{
if (row[i]!=1&&digLeft[k+i-1]!=1&&digRight[n+k-i]!=1)
{
col[k]=i;
row[i]=digLeft[k+i-1]=digRight[n+k-i]=1;
if (k==n)
{
for (int j=1;j<=n;++j)
cout<<col[j]<<' ';
cout<<endl;
++times;
}
else queen_all(k+1,n);
row[i]=digLeft[k+i-1]=digRight[n+k-i]=0;
}
}
}
最后 --- *** 八皇后能帮助我们能够理解回溯法的思想,是一次不错的训练。 感觉皇后问题比快排和搜索简单。
学习自:**C++程序设计**|思想与方法(我的教材)