去年师兄面试新浪,上来就是一道迷宫题,相信大家都知道用回溯法来解决,但是要在半小时内写出正确的代码对我等菜鸟来说也不容易。
下面思考一下回溯法的思路:
//下面部分内容摘自http://fuliang.iteye.com/blog/164686,作者fuliang
回溯法解题包括以下三步:
1、针对问题,定义解空间
2、确定易于搜索的解空间结构
3、以深度优先的方式搜索解空间,并在搜索的过程中进行剪枝
回溯法通常在解空间树上进行搜索,而解空间树通常有子集树和排列树。
结果的保存通常有两种形式:
(一)用m个k元组表示m种不同的解。其中,每组中的元素是[1,n]中的一个元素。
(二)用m个n元组表示m种不同的解。因为所有的节点都包含在每个解的表示中,每组中的元素只有两种情况,被选用和不被选用。子集合树的一般框架如下:
- void backtrack(int t){
- if(t > n) output(x);
- else{
- for(int i = f(n,t); i <= g(n,t);i++){ //其中f(n,t),g(n,t)表示当前扩展结点处未搜索过的子树的起始标号和终止标号,
- x[t] = h(i); //h(i)表示当前扩展节点处,x[t]第i个可选值
- if(constraint(t) && bound(t)) backtrack(t+1); //递归调用
- }
- }
- }
- #include<iostream>
- using namespace std;
- int s[3] = {1,3,6};
- int x[3];
- int N = 3;
- void print(){
- for(int j = 0; j < N; j++)
- if(x[j] == 1)
- cout << s[j] << " ";
- cout << endl;
- }
- void subset(int i){
- if(i >= N){
- print();
- return;
- }
- x[i] = 1;//搜索右子树
- subset(i+1);
- x[i] = 0;//搜索左子树
- subset(i+1);
- }
- int main(){
- subset(0);
- return 0;
- }
排列树的算法框架:
- void backtrack(int t){
- if(t > n) output(x);
- else{
- for(int i = f(n,t); i <= g(n,t);i++){
- swap(x[t],x[i]);
- if(constraint(t) && bound(t)) backtrack(t+1);
- swap(x[t],x[i]);
- }
- }
- }
- #include<iostream>
- using namespace std;
- int a[4] = {1,2,3,4};
- const int N = 4;
- void print(){
- for(int i = 0; i < N; i++)
- cout << a[i] << " ";
- cout << endl;
- }
- void swap(int *a,int i,int j){
- int temp;
- temp = a[i];
- a[i] = a[j];
- a[j] = temp;
- }
- void backtrack(int i){
- if(i >= N){
- print();
- }
- for(int j = i; j < N; j++){
- swap(a,i,j);
- backtrack(i+1);
- swap(a,i,j);
- }
- }
- int main(){
- backtrack(0);
- return 0;
- }