LintCode 汉诺塔

题目链接:https://www.lintcode.com/problem/tower-of-hanoi/description

题目大意

  经典递归问题。

分析

  由于是经典问题了,这里不讨论用递归实现,也不讨论用栈模拟实现,只讨论纯迭代实现。
  首先用 L, M, R 来标记左柱子,中柱子,右柱子。
  我们知道汉诺塔问题与二进制是密不可分的,“n-圆盘汉诺塔问题”最少只需要$2^n - 1$步,而且如果 n 为奇数,第一步必然是 L->R;如果 n 为偶数,第一步必然是 L->M。
  现在我们定义三个操作,每个操作相当于走一步:
  1. 把 M 标记和 R 标记互换,执行 L->R。
  2. 把 L 标记和 M 标记互换,执行 L->R。
  3. 把 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:我是不知道为啥,我是闲着无聊找规律找到的。

代码如下

 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 };
View Code
原文地址:https://www.cnblogs.com/zaq19970105/p/11341166.html