zoukankan      html  css  js  c++  java
  • 汉诺塔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
  • 相关阅读:
    623. Add One Row to Tree 将一行添加到树中
    771. Jewels and Stones 珠宝和石头
    216. Combination Sum III 组合总数三
    384. Shuffle an Array 随机播放一个数组
    382. Linked List Random Node 链接列表随机节点
    向github项目push代码后,Jenkins实现其自动构建
    centos下安装Jenkins
    python提取批量文件内的指定内容
    批处理实现:批量为文件添加注释
    python抓取每期双色球中奖号码,用于分析
  • 原文地址:https://www.cnblogs.com/zaq19970105/p/10759266.html
Copyright © 2011-2022 走看看