• 【基本算法题-2022.7.30】9. 奇怪的汉诺塔


    每日一题包含七大板块,现在从最基本的算法题开始,此类题型包括位运算、递推、递归、二分、排序、贪心等,从简单到复杂,跟我一起从点滴积累,到最终一举成名,打遍天下!✨


    💻基本算法题9. 奇怪的汉诺塔

    汉诺塔问题,条件如下:

    1、这里有 A、B、C 和 D 四座塔。

    2、这里有 n 个圆盘,n 的数量是恒定的。

    3、每个圆盘的尺寸都不相同。

    4、所有的圆盘在开始时都堆叠在塔 A 上,且圆盘尺寸从塔顶到塔底逐渐增大。

    5、我们需要将所有的圆盘都从塔 A 转移到塔 D 上。

    6、每次可以移动一个圆盘,当塔为空塔或者塔顶圆盘尺寸大于被移动圆盘时,可将圆盘移至这座塔上。

    请你求出将所有圆盘从塔 A 移动到塔 D,所需的最小移动次数是多少。
    汉诺塔塔参考模型
    输入格式
    没有输入

    输出格式
    对于每一个整数 n,输出一个满足条件的最小移动次数,每个结果占一行。

    数据范围
    1≤n≤12

    输入样例:

    没有输入
    
    • 1

    输出样例:

    参考输出格式
    
    • 1

    🍀题解 — DP+递推

    对于汉诺塔问题,我们究其根底

    约定:

    1. 我们用ABCDE来命名塔的名字,
    2. 默认初始的圆盘都在A塔上,最终要移动到最后一个塔上。
    3. d 数组存放3个塔的结果,f 数组存放4个塔的结果, g 数组存放5个塔的结果

    两个塔(AB)

    如果只有两个塔,那么只有圆盘个数为一时,答案为1,其余答案为0

    三个塔(ABC)

    如果有三个塔,移动时我们需要借助二塔里的结论

    如果要移动 n 个圆盘,我们需要在三塔的情况下,将上面 n - 1 个较小圆盘移动到B塔,在将一个大圆盘移动到C塔,最后在将 n - 1 个圆盘在三塔的情况下从B移动到C塔

    结论:d(n) = d(n - 1) + 1 + d(n - 1)

    四个塔(ABCD)
    解决完三塔问题,四塔问题将于三塔类似

    如果要移动n个圆盘从A到D的话,我们的解决方法是将一部分圆盘(i个圆盘)先移动到B(或者C),因为这前几个圆盘都是非常小的,后面剩下的大圆盘不能压在上面,所以放小圆盘这个塔暂时不能使用

    那么问题将会变成,怎么在三塔情况下将n - i 个圆盘从A移动到D,这时可以用三塔的结论;

    问题1:我们先移动的一部分圆盘到底是几个呢,我们需要枚举,最终答案取最小值。

    结论:先把前 i 个盘子在四塔情况下移动到B,剩下的盘子在三塔情况下移动到D,最后在将那 i 个小的盘子在四塔情况下从B移动到D。

    f(n) = min(f(n), f(i) + d(n - i) + f(i)) 0 <= i <= n;

    对于这道题:

    首先,可以初步确定,这是一道递归/递推的题目。

    我们先考虑三个塔的汉诺塔问题,最优秀方案:必然是先挪走n-1个圆盘,然后再挪走圆盘N,

    因此可以得出递推方程也就是 d[i]=d[i-1]*2+1;

    之所以要乘以2,是因为第一次挪到第二个塔,然后还要挪移回到第三个塔,下面四个塔也是这样的

    接着考虑四塔问题,我们可以这么思考,首先挪走j个塔,也就是有四个塔可以选择,然后再挪走剩下的n-j个塔,此时有三个塔可以选择,因此这就是我们的状态转移方程:

    f[i]=min(f[i],f[j]*2+d[n-j]);其中i表示当前一共有几个塔,也就是上文所说的n

    📝代码展示

    #include 
    using namespace std;
    int d[21],f[21],i,j;
    int main()
    {
        for (i=1;i<=12;i++)
            d[i]=2*d[i-1]+1;
        memset(f,0x3f,sizeof(f));
        f[0]=0;
        for (i=1;i<=12;i++)
            for (j=0;j<i;j++)
                f[i]=min(f[i],f[j]+f[j]+d[i-j]);
        for (i=1;i<=12;i++)
            cout<<f[i]<<endl;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    【🎯知识点:递推算法】

    递推 是指将一个看似复杂,难以求解的问题一步步的转换成小问题,最后到达一个(或若干个)基本解,这些基本解很好想出来,也有的是人为规定的,然后再依赖这些基本解一步一步反向求解最初的大问题的过程。

    举一个最简单和常见的例子,斐波那契数列,这个数列的每一项等于前面两项之和。如下:

    {1,1,2,3,5,8,13…}

    如果让你直接求斐波那契数列的第100个数f(100),很难直接想出来,但是我们可以通过找到如下的递推关系:f(n)=f(n−1)+f(n−2),并且确定基本解f(1)=1f(2)=1(因为递推关系只依赖前面两项,所以只求出基本的两项即可),之后就可以求出f(3),再用f(2)+f(3)求f(4),最后求解到f(100)。

    很多问题可以找到递推关系,所以这个工具很常用,比如解决具有重叠子问题的递推关系的算法叫“动态规划”,它出现在很多面试题和算法竞赛当中 。


    持续更新,喜欢的话欢迎点赞👍、收藏⭐️+关注✌️哟~

  • 相关阅读:
    vue-cil之elementui、vuex(任务管理器)
    唤醒桌面应用中休眠的宇宙结构(一)
    whip和whep
    【第一周】数学作业(贷款问题)
    人工智能基础_机器学习045_逻辑回归的梯度下降公式推导_更新公式---人工智能工作笔记0085
    BeanUtils.copyProperties的用法
    基于某钉探索针对CEF框架的一些逆向思路
    类和对象(详)
    2012年下半年 系统架构设计师 下午试卷 II
    webpack定制化 高级配置[热更新、热打包、别名、调试]
  • 原文地址:https://blog.csdn.net/weixin_46020266/article/details/126079356