汉诺塔问题
次数问题
#include <iostream> using namespace std; /* 将n个盘子从x搬到z 可以转化为 先n上方n-1个盘子搬到y,再把n这个盘子搬到z,最后将n-1个盘子从y搬到z。依次类推。 即f(n) 的问题可以转化为f(n-1)的问题,...,f(1); 三根柱子 分别用 x y z 表示 伪代码如下: int fz(int n) { if(n == 1) return 1; else return fy(n-1) + 1 + fz(n-1); } */ unsigned long long f(int n) { if (n == 1) return 1; else return 2 * f(n - 1) + 1; } int main() { // test cout << "step cnt " << f(3) << endl; // 3个盘子 从0搬运到2 cout << "step cnt " << f(4) << endl; // 4个盘子 从0搬运到2 cout << "step cnt " << f(64) << endl; // 64个盘子 从0搬运到2 /* step cnt 7 step cnt 15 step cnt 18446744073709551615 // 这个数字超过了long long 的范围,这里用unsigned long long */ }
64个金盘,如果每秒移动一个,那么按照它的这个规则需要5849亿年。
搬运步骤问题
我们假设搬运n个盘子,且他们的序号为1-n。三个柱子的索引为0,1,2。
使用(plateNo,fromIdx,toIdx) 三个数的元组来表示每一次搬运的过程。有了这个数据结构,我们也可以用代码可视化的展示汉诺塔的搬运过程。
则有如下递归程序来描述搬运过程
#include <iostream> #include <vector> using namespace std; void f(int n,int fromIdx,int toIdx,vector<vector<int>>& vvRet) { if(n == 1) vvRet.push_back({1,fromIdx,toIdx}); else { f(n-1,fromIdx,3-fromIdx-toIdx,vvRet); vvRet.push_back({n,fromIdx,toIdx}); f(n-1,3-fromIdx-toIdx,toIdx,vvRet); } } int main() { // test vector<vector<int>> vvRet; //f(3,0,2,vvRet); // 3个盘子 从0搬运到2 /* ( 1, 0, 2 ) ( 2, 0, 1 ) ( 1, 2, 1 ) ( 3, 0, 2 ) ( 1, 1, 0 ) ( 2, 1, 2 ) ( 1, 0, 2 ) */ f(4,0,2,vvRet); // 4个盘子 从0搬运到2 /* ( 1, 0, 1 ) ( 2, 0, 2 ) ( 1, 1, 2 ) ( 3, 0, 1 ) ( 1, 2, 0 ) ( 2, 2, 1 ) ( 1, 0, 1 ) ( 4, 0, 2 ) ( 1, 1, 2 ) ( 2, 1, 0 ) ( 1, 2, 0 ) ( 3, 1, 2 ) ( 1, 0, 1 ) ( 2, 0, 2 ) ( 1, 1, 2 ) */ for(auto item:vvRet) { cout << "( "<<item[0]<<", "<<item[1]<<", "<<item[2]<<" )"<<endl; } }