汉诺塔I && II

汉诺塔I

题目链接:https://www.nowcoder.com/questionTerminal/7d6cab7d435048c4b05251bf44e9f185

题目大意:

  略

分析:

  利用汉诺塔与二进制的关系来做。

  如何用二进制解汉诺塔:https://www.bilibili.com/video/av7398130/

代码如下:

 1 class Hanoi {
 2 public:
 3     // 计算x的二进制位数 
 4     inline int getBits(int x) {
 5         int cnt = 1;
 6         while(x >>= 1) ++cnt;
 7         return cnt;
 8     } 
 9     
10     vector<string> getSolution(int n) {
11         vector< string > ans;
12         string s[3] = {"left", "mid", "right"};
13         vector< int > arr;
14         arr.resize(n, 0);
15         // tot表示总移动次数
16         int tot = (1 << n) - 1;
17         int cnt = 0;
18         while(cnt++ < tot) {
19             int lowbit = cnt & (-cnt);
20             int bitlen = getBits(lowbit) - 1;
21             int b = 1 + (n - bitlen) % 2;// 偏移,b = 1往右,b = 2往左
22             ans.push_back("move from " + s[arr[bitlen]] + " to " + s[(arr[bitlen] + b) % 3]);
23             arr[bitlen] = (arr[bitlen] + b) % 3;
24         }
25         return ans;
26     }
27 };
View Code

 

汉诺塔II

题目链接:https://www.nowcoder.com/questionTerminal/b2d552cd60b7415fad2612a32e799812?toCommentId=2927834

题目大意:

  略

分析:

先给出4个盘子的表(三根柱子的序号分别为0, 1, 2):

容易看出n个盘子需要移动2n次。

  首先我们看红线分割的两块,令8~15行的0号,1号,2号盘子的位置加上2再模3,他们的数值刚好等于0~7行的0号,1号,2号盘子的位置。

  再看绿线分割的0~7行,另4~7行的0号,1号盘子的位置加上1再模3,他们的数值刚好等于0~3行的0号,1号盘子的位置。

  发现规律了没有?

  比如有汉诺塔的位置序列[2, 1, 1, 2],序列最后一个数为2,于是step([2, 1, 1, 2])就等于1000B + step([(2 + 2) % 3, (1 + 2) % 3,  (1 + 2) % 3]) = 1000B + step([1, 0, 0]),然后step([1, 0, 0])的最后一个数为0,于是step([1, 0, 0]) = step([1, 0]),直接往前进,并不需要上移,同理step([1, 0]) = step([1]), 对于step([1]),只有一个数字,直接取值,所以step([2, 1, 1, 2])最终等于1001B

  再比如有汉诺塔的位置序列[2, 0, 1, 2],序列最后一个数为2,于是step([2, 0, 1, 2])就等于1000B + step([(2 + 2) % 3, (0 + 2) % 3,  (1 + 2) % 3]) = 1000B + step([1, 2, 0]),然后step([1, 2, 0])的最后一个数为0,于是step([1, 2, 0]) = step([1, 2]),step([1, 2])的最后一个数字是2,于是step([1, 2]) = 10B + step([(1 + 2) % 3]) = 10B + step([0]), 对于step([0]),只有一个数字,直接取值,所以step([2, 1, 1, 2])最终等于1010B

  简单来说,就是末尾数字为0,就不变;末尾数字不为0,就让前面的数字加上这个数字再模3,然后求子问题,同时要加上这一位的权值,比如它是第5个数字,就要加上10000B;如果是第3个数字,就要加上100B

  不要问我原理,我是结合二进制找规律找出来的。

代码如下:

1 class Hanoi {
2 public:
3     int chkStep(vector<int> &arr, int n, int b = 0) {
4         if(n == 0) return 0;
5         int tmp = (arr[n - 1] + b - 1) % 3 ;
6         return (1 << (n - 1)) * (tmp != 0) + chkStep(arr, n - 1, b + tmp);
7     }
8 };
View Code

 

posted @ 2019-04-23 21:52  梦樱羽  阅读(463)  评论(0编辑  收藏  举报
Live2D