一、什么是回溯法
回溯法是一种选优收索法,按照选优条件深度优先收索。如果发现该结点不是最优结点或死结点,就退回上一步重新选择。能进则进,不进则换,不换则退。
二 、算法要素
(1)首先要确定解的形式==解空间:所有可能解组成的空间
(2)想象解空间的组织结构(可以简单理解为一个树)
(3)探索解空间(其中包含一个重要的概念:隐约束(剪枝函数:约束条件+限界函数))
剪枝函数:减掉得不到可行解或最优解的分支
*扩展结点:一个正在生成孩子得结点
*活结点:一个自身已生成,但孩子还没有全部生成的结点
*死结点:一个所有孩子都已生成的节点
三、算法设计
(1)定义解空间:n皇后问题就是定义一个n元组:{x1,x2,………,xn}
(2)解空间的组织结构:可以看成一个n叉树,树的深度为n。
(3)收索解空间:
*约束条件 if(x[t]==x[j] || t-j==x[t]-x[j]) break;
*限界条件 不需要
*收索过程:从根开始,以深度优先遍历的方式进行收索。根结点是活结点,并且是当前的扩展结点。在扩展过程中,当前的扩展结点沿纵深方向移向一个新节点,判断该节点是否满足隐约束。if(0) 则该节点为活结点,并且成为扩展结点,继续深一层的收索;if(1) 则换到该结点的兄弟节点继续收索,如果没有兄弟结点或者都收索完了,则该节点为死结点,收索回溯到父节点—-直到根结点变成死结点
四、代码(趣学算法–陈小玉编注内的代码)
#include<iostream>
#include<cmath>
#define M 105
using namespace std;
int n;
int x[M];
int countn;
bool Place(int t){
bool ok=true;
for(int j=1;j<t;j++){
if(x[t]==x[j]||t-j==fabs(x[t]-x[j]))
{
ok=false;
break;
}
}
return ok;
}
void Backtrack(int t){
if(t>n){
countn++;
for(int i=1;i<=n;i++) cout<<x[i]<<" ";
cout<<endl;
cout<<"—————————"<<endl;
}
else
for(int i=1;i<=n;i++){
x[t]=i;
if(Place(t))
Backtrack(t+1);
}
}
int main(){
cout<<"请输入皇后的个数:";
cin>>n;
countn=0;
Backtrack(1);
cout<<"答案个数:"<<countn<<endl;
return 0;
}