汉诺塔,n皇后,跳马问题-汇总
递归,回溯,深搜或者广搜。 http://www.cnblogs.com/tanky_woo/
1.汉诺塔
////////////////////////////////////////////////
/*
汉诺塔
题目:
假设有A, B, C 3个轴,有n个直径各不相同,
从小到大依次编号为1,2,3,…,n的圆盘
按照从小到大的顺序叠放在A轴上。现在要求
将这n个圆盘移至C轴上并仍然按照同样顺序
叠放,但圆盘移动时必须遵守下列规则:
1.每次只能移动一个圆盘,它必须位于某个
轴的顶部。
2.圆盘可以插在A,B,C中任一轴上。
3.任何时刻都不能将一个较大的圆盘压在较小
的圆盘之上。
*/
///////////////////////////////////////////////

经典的问题,属于递归的入门级问题,但是同样不好分析,在n<=4以内还可以模拟下汉诺塔的实现,当n>=5时就不太现实了,让我们来看看汉诺塔当圆盘个数n时有多少组解? 按照传说来看:n=64,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。
但是这毕竟是神话,不过当把64个金片全部放到另外一根针时,确实要很长很长一段时间。
让我们来看看需要多长时间。
首先,我们找出递推关系:
f(n + 1) = 2*f(n) + 1
至于这个怎么得到的可以画图看看。
把递推关系算出来后,也就是:
f(n) = 2^n-1
那么当n=64时,是多少?
f(64)= 2^64-1=18446744073709551615
假如每秒钟一次,共需多长时间呢?一年大约有 31536926 秒,计算表明移完这些金片需要5800多亿年,比地球寿命还要长,事实上,世界、梵塔、庙宇和众生都已经灰飞烟灭。
/*递归实现*/ #include <iostream> using namespace std; //把n号圆盘从x移到y,并打印出。 void Move(int n, char x, char y) { cout<< "把" << n << "号圆盘从" << x << "移动到" << y << endl; } //把前n个通过b从a移到c void Hanoi(int n, char a, char b, char c) { if(n == 1) Move(1, a, c); else { Hanoi(n-1, a, c, b); Move(n, a, c); Hanoi(n-1, b, a, c); } } int main() { int n; cout << "输入n的大小: "; cin >> n; Hanoi(n, 'a', 'b', 'c'); cout << "Ok!" << endl << "By Tanky Woo." << endl; return 0; }
2.n皇后
作为搜索类题目还是老问题:
1.边界条件。
2.对每种情况都得遍历到,可以用解答树分析。
3.剪枝 http://www.wutianqi.com/?p=1341(搜索与剪枝)
4.辅助空间的变化。回溯前和回溯后的变化。
如果不用辅助空间的回溯当然就不需要注意辅助空间的问题了。
以下是n皇后的源码:
/* * n皇后问题 * Tanky Woo */ #include <iostream> using namespace std; int queen[100]; int n; // n皇后 int tot = 0; //解法种数 // www.wutianqi.com void search(int cur) { if(cur == n) //递归边界。符合要求,输出。 { tot++; for(int i=0; i<n; ++i) cout << queen[i] << " "; cout << endl; } else { for(int i=0; i<n; ++i) { bool flag = 1; queen[cur] = i; // 尝试把第cur行的皇后放在第i列 for(int j=0; j<cur; ++j) // 检查是否和前面的皇后冲突 if(queen[cur] == queen[j] // 同一列 || cur-queen[cur] == j-queen[j] // 正对角线 || cur+queen[cur] == j+queen[j]) // 反对角线 { flag = 0; break; } if(flag) search(cur+1); // 如果合法,继续 } } } int main() { cout << "输入皇后个数n: "; cin >> n; search(0); cout << "共有" << tot << "种解." << endl << "By Tanky Woo." << endl; return 0; }
自己又重新写一个:
#include<iostream> #include<cstdlib> using namespace std; #define N 20 int n; //皇后个数 int sum = 0; //可行解个数 int x[N]; //皇后放置的列数 int place(int k) { int i; for(i=1;i<k;i++)//每个皇后有k个位置(列)可放 //判断两个皇后是否在同一列或同一斜线 if(abs(k-i)==abs(x[k]-x[i]) || x[k] == x[i])//k和i分别表示两个皇后行号 return 0; return 1; } int queen(int t) { if(t>n && n>0) sum++; //当放置的皇后超过n时,可行解个数加1,此时n必须大于0 else { for(int i=1;i<=n;i++) { x[t] = i; //标明第t个皇后放在第i列 if(place(t)) queen(t+1); //如果可以放在某一位置,则继续放下一皇后 } } return sum; } int main() { int t; cin>>n; t = queen(1); if(n == 0) t = 0;//如果n=0,则可行解个数为0 cout<<t; //system("pause"); return 0; }
3.跳马问题:
据说此题证明可以用组合数学中的哈密顿环。
组合数学确实博大精深,看过一段时间的组合数学,感觉和实际联系的很多,Orz.
此题有两种版本: ①:给定一个N*N的棋盘,起始点在(0,0)处,要求求出有多少种方法,可以不重复的遍历棋盘上所有的点。
规则:1.马走日字
2.走过的点就不能再走了 此题和上面的n皇后类似,是标准的DFS。
分析:从起始点开始,每次遍历八种方向,直到边界条件,并输出。 以下是跳马问题一的源码:/*马跳棋盘问题*/
#include <iostream> using namespace std; const int N = 10; int a[N][N] = {0}; int cnt = 0; void Horse(int a, int b, int t); // www.wutianqi.com int main() { int i = 0, j = 0, t = 1; a[i][j] = t; Horse(i, j, step+1); cout << cnt << endl; cout << "By Tanky Woo.\n"; return 0; } void Horse(int a, int b, int t) { int x[4] ={-2, -1, 1, 2}, y[4] = {-2, -1, 1, 2}; if(t == N*N+1) cnt++; for(int i=0; i<4; ++i) for(int j=0; j<4; ++j) { if(x[i]==y[j] || x[i]==-y[j]) continue; if(a+x[i]>=0 && a+x[i]<N && b+y[j]>=0 && b+y[j]<N && board[a+x[i]][b+y[j]]==0) { a[a+x[i]][b+y[j]] = t; Horse(a+x[i], b+y[j], t+1); a[a+x[i]][b+y[j]] = 0; } } }
第二个版本: ②:设有右图所示的一个棋盘,在棋盘上的A点,有一个中国象棋的马,并约定马走的规则:
规则:1. 马走日字
2. 马只能向右走。
试找出所有从A到B的途径。
#include<iostream> using namespace std; int n,m,x1,x2,y1,y2; bool dfs(int i,int j) { if(i==x2 && j==y2)return 1;//如果到达,返回1 if(j>=y2)return 0;//因为不能往回走,所以横坐标一旦超限就走不到了 if(i+2<n && j+1<m)if(dfs(i+2,j+1))return 1; if(i+1<n && j+2<m)if(dfs(i+1,j+2))return 1; if(i-1>=0 && j+2<m)if(dfs(i-1,j+2))return 1; if(i-2>=0 && j+1<m)if(dfs(i-2,j+1))return 1;//四种走法 return 0;//以上都没走到,返回0 } int main() { cin>>n>>m>>x1>>y1>>x2>>y2; if(dfs(x1,y1))cout<<"yes";//能走到,输出yes else cout<<"no"; return 0; }

浙公网安备 33010602011771号