回溯法的分析及N皇后问题
2015-03-27 23:31
169 查看
所谓的回溯法实质就是深度优先搜索,在每个路径上一直向前寻找,到达某个结点不满足约束函数时,就回溯到其父结点,从父结点的其他子树向下寻找。
当某条路径可以一直伸展到叶子结点时,就在叶子结点上继续遍历,遍历的结果必然是叶子结点的某种情况不满足约束函数,这时就要回溯到叶子结点的父结点,从父结点的其他子树向下寻找,这个子树同样也要遍历叶子结点的所有情况。
回溯实际上是递归的展开,但实际上两者的指导思想并不一致。
打个比方,递归好比是一个军队要通过一个迷宫,到了第一个分岔口,有3条路,将军命令3个小队分别去探哪条路能到出口,3个小队沿着3条路分别前进,各自到达了路上的下一个分岔口,于是小队长再分派人手各自去探路——只要人手足够(对照而言,就是计算机的堆栈足够),最后必将有人找到出口,从这人开始只要层层上报直属领导,最后,将军将得到一条通路。所不同的是,计算机的递归法是把这个并行过程串行化了。
而回溯法则是一个人走迷宫的思维模拟——如果他没有办法在分岔口留下标记,他只能寄希望于自己的记忆力。
1.递归回溯法
一定要注意:void型递归函数的返回是隐形的,即当前层条件不满足,就会自动返回到上一层。
下面的Queen代码中,如果当前层没有找到合适的位置放置皇后,即循环体中的部分就不会执行,自然也不会执行循环体中的递归函数 Queen(row+1); ,说明上一行选择的列不合适,递归返回到上一层,执行Queen_array[row]=0; 然后col++。重新查找合适的列,如果本层递归仍然查找不到,就继续向上一层回溯,执行Queen_array[row]=0; 然后col++ ……
2.回溯法
由递归回溯法的分析,我们可以知道,如果一直向上一层回溯,使得回溯到最上层(第一行),col 也增加到了最后一列,但仍不合适,程序仍要向上层回溯,可是没有上层函数了,此时就退出了程序,我们可以利用这一点(把行号作为循环条件,如果行号小于1了则退出循环——此时就是回溯到了最上层仍找不到合适的列还想再向上找的情况)作为循环的条件而不需要递归。
程序如下:
3.精简版 ( 由1演化而来 )
当某条路径可以一直伸展到叶子结点时,就在叶子结点上继续遍历,遍历的结果必然是叶子结点的某种情况不满足约束函数,这时就要回溯到叶子结点的父结点,从父结点的其他子树向下寻找,这个子树同样也要遍历叶子结点的所有情况。
回溯实际上是递归的展开,但实际上两者的指导思想并不一致。
打个比方,递归好比是一个军队要通过一个迷宫,到了第一个分岔口,有3条路,将军命令3个小队分别去探哪条路能到出口,3个小队沿着3条路分别前进,各自到达了路上的下一个分岔口,于是小队长再分派人手各自去探路——只要人手足够(对照而言,就是计算机的堆栈足够),最后必将有人找到出口,从这人开始只要层层上报直属领导,最后,将军将得到一条通路。所不同的是,计算机的递归法是把这个并行过程串行化了。
而回溯法则是一个人走迷宫的思维模拟——如果他没有办法在分岔口留下标记,他只能寄希望于自己的记忆力。
1.递归回溯法
一定要注意:void型递归函数的返回是隐形的,即当前层条件不满足,就会自动返回到上一层。
下面的Queen代码中,如果当前层没有找到合适的位置放置皇后,即循环体中的部分就不会执行,自然也不会执行循环体中的递归函数 Queen(row+1); ,说明上一行选择的列不合适,递归返回到上一层,执行Queen_array[row]=0; 然后col++。重新查找合适的列,如果本层递归仍然查找不到,就继续向上一层回溯,执行Queen_array[row]=0; 然后col++ ……
#include<stdio.h> #include<math.h> #define N 8 int count=0; int Queen_array ={0}; int Pos_Feasible(int row,int col) { int i; for(i=0;i<row;i++){ //col不能用Queen_array[row]代替,因为此时Queen_array[row]=0,还未被赋值为col if(col==Queen_array[i]||(abs(col-Queen_array[i])==row-i)) return 0; } return 1; } void print_result( ) { int i; for(i=0;i<N;i++){ printf("%d ",Queen_array[i]+1); } printf("\n"); } /*当递归回溯到上一层,再从上一层递归到这一层时,这一层的所有临时数据被销毁,重新赋值*/ void Queen(int row) { int col; for(col=0;col<N;col++){ if(Pos_Feasible(row,col)){ //在这一行时Queen_array[row]=0,还未被赋值为col Queen_array[row]=col; if(row==N-1){ print_result( ); count++; } Queen(row+1); } } //如果这一层没找到合适的 } int main() { Queen(0); printf("total = %d\n", count); return 0; }
2.回溯法
由递归回溯法的分析,我们可以知道,如果一直向上一层回溯,使得回溯到最上层(第一行),col 也增加到了最后一列,但仍不合适,程序仍要向上层回溯,可是没有上层函数了,此时就退出了程序,我们可以利用这一点(把行号作为循环条件,如果行号小于1了则退出循环——此时就是回溯到了最上层仍找不到合适的列还想再向上找的情况)作为循环的条件而不需要递归。
程序如下:
#include<stdio.h> #include<math.h> int x[100]; int count=0; bool place(int k)//考察皇后k放置在x[k]列是否发生冲突 { int i; for(i=1;i<k;i++) if(x[k]==x[i]||abs(k-i)==abs(x[k]-x[i])) return false; return true; } void queue(int n) { int i,k; for(i=1;i<=n;i++) x[i]=0; k=1; while(k>=1) { x[k]++; //在下一列放置第k个皇后 while(x[k]<=n&&!place(k)) x[k]=x[k]+1;//搜索下一列 if(x[k]<=n&&k==n)//得到一个输出 { for(i=1;i<=n;i++) printf("%d ",x[i]); printf("\n"); count++; //return;//若return,就无法在叶子结点上继续遍历( x ++; )<span style="font-family: Arial, Helvetica, sans-serif;">,就找不到可以让它回溯的点,也就无法回溯,则只求出其中一种解</span> } else if(x[k]<=n&&k<n) k++;//放置下一个皇后(下一行) else { x[k]=0;//重置x[k],回溯。必须要重置,因为当回溯到上一层找到合适列(路径)时,还要伸展到这一层从头(第0列,col=0)开始寻找 k--; } } printf("%d\n",count); } int main() { int n; printf("输入皇后个数n:\n"); scanf("%d",&n); queue(n); return 0; }
3.精简版 ( 由1演化而来 )
#include<stdio.h> #include<math.h> #define N 8 int count=0; int Queen_array ={0}; void print_result( ) { int i; for(i=0;i<N;i++){ printf("%d ",Queen_array[i]+1); } printf("\n"); } void Queen(int row) { if(row==N){ //注意是N,不是 N-1 count++; print_result( ); //执行完这一步就返回上一层递归继续col++ } else for(int col=0;col<N;col++){ int ok=1; Queen_array[row]=col; for(int i=0;i<row;i++){ if(col==Queen_array[i]||abs(col-Queen_array[i])==row-i){ ok=0;break; } } if(ok) Queen(row+1); } } int main() { Queen(0); printf("total = %d\n", count); return 0; }
相关文章推荐
- 回溯法特点分析以及经典N皇后问题
- 【算法分析】回溯法解八皇后问题(n皇后问题)
- 算法分析与设计回溯法之n皇后问题
- 关于递归和回溯的说明以及8皇后问题的递归流程分析
- 国际象棋“皇后”问题的回溯算法[C#源码分析]
- [HDU 2553]--N皇后问题(回溯)/N皇后问题的分析
- 国际象棋“皇后”问题的回溯算法
- 国际象棋“皇后”问题的回溯算法
- 关于N皇后问题高效试探回溯算法的分析
- 回溯——n皇后问题
- 回溯法求解8皇后问题
- 回溯法求解n皇后问题
- 国际象棋“皇后”问题的回溯算法
- 国际象棋“皇后”问题的回溯算法
- 回溯——n皇后问题 收藏
- 8皇后问题(回溯)
- 国际象棋“皇后”问题的回溯算法
- 国际象棋“皇后”问题的回溯算法
- 国际象棋“皇后”问题的回溯算法
- 关于N皇后问题高效试探回溯算法的分析