题目链接:https://www.lintcode.com/problem/tower-of-hanoi/description
题目大意
经典递归问题。
分析
由于是经典问题了,这里不讨论用递归实现,也不讨论用栈模拟实现,只讨论纯迭代实现。
首先用 L, M, R 来标记左柱子,中柱子,右柱子。
我们知道汉诺塔问题与二进制是密不可分的,“n-圆盘汉诺塔问题”最少只需要$2^n - 1$步,而且如果 n 为奇数,第一步必然是 L->R;如果 n 为偶数,第一步必然是 L->M。
现在我们定义三个操作,每个操作相当于走一步:
- 把 M 标记和 R 标记互换,执行 L->R。
- 把 L 标记和 M 标记互换,执行 L->R。
- 把 L 标记和 M 标记互换,把 M 标记和 R 标记互换,执行 L->R。
于是这个问题可以这样解决,去掉第一步,还剩$2^n - 2$步,如果我们把走两步算作一大步,那么还剩$2^{n - 1} - 1$大步,我们令$i:1 ightarrow2^{n - 1} - 1$依次模拟每个大步,如果 i 的最低 2 进制位的位置是偶数位置时,就执行 2 次操作 3,否则执行 1 次操作 1 和 1 次操作 2。
神奇的是,这样做居然是可行的。
PS:我是不知道为啥,我是闲着无聊找规律找到的。
代码如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public: 3 string L = "A", M = "B", R = "C"; 4 vector< string > ans; 5 /** 6 * @param n: the number of disks 7 * @return: the order of moves 8 */ 9 vector<string> towerOfHanoi(int n) { 10 if(n % 2 == 0) swap(M, R); 11 ans.push_back(step(L, R)); 12 13 n = (((1 << n) - 2) >> 1); 14 for(int i = 1; i <= n; ++i) { 15 // 如果i的最低2进制位的位置是偶数,就执行2次操作3,否则执行1次操作1和一次操作2 16 if(__builtin_ffs(i) % 2 == 0) { 17 op3(); 18 op3(); 19 } 20 else { 21 op1(); 22 op2(); 23 } 24 } 25 26 return ans; 27 } 28 29 inline string step(string x, string y) { 30 return "from " + x + " to " + y; 31 } 32 33 inline void op1() { 34 swap(M, R); 35 ans.push_back(step(L, R)); 36 } 37 38 inline void op2() { 39 swap(L, M); 40 ans.push_back(step(L, R)); 41 } 42 43 inline void op3() { 44 swap(M, L); swap(R, M); 45 ans.push_back(step(L, R)); 46 } 47 };