动态规划算法之汉诺塔问题-其一

题目描述

传说中有一座位于印度寺庙的塔,塔内有三个柱子,其中一个柱子上摞着n个大小不同的圆盘,从底部开始呈递减的形式。目标是将这些圆盘按照规定的规则从初始柱子(通常是最左边的柱子)移动到目标柱子(通常是最右边的柱子),并且在整个过程中遵守以下规则:

1、每次只能移动一个圆盘。
2、不能将较大的圆盘放在较小的圆盘

求移动到右边柱子的最少需要的移动次数。

问题分析

以一个三阶汉诺塔为例,我们先观察其移动过程

再看下四阶的汉诺塔移动过程

从上面的两个例子中,我们可以归纳总结,n阶的汉诺塔,在移动时,都需要经过上面红框里面的三步

1、先将前面n-1个圆盘移到中间的柱子上;

2、再将最大的圆盘从左边移到右边的柱子上;

3、最后将中间柱子上的n-1个圆盘移到右边的柱子上;

而n-1阶又可以由n-2阶推导出,以此类推,最后可推到1阶汉诺塔,然后从1阶的最少移动次数为1出发,算出2阶的最少移动次数为 1+1+1,3阶的最少移动次数为 3+1+3,以此类推。其实不难发现,n阶汉诺塔的最少移动次数其实就等于(2^n) -1,写成函数表达式则是f(n)=f(n-1)+1+f(n-1)表达式中的三部分正好对应上面的三个步骤,所以经过上述分析,怎么用代码实现是不是呼之欲出。

代码实现

 /**
     *
     * @param n 代表汉诺塔阶数
     * @return 返回最少移动次数
     */
    private int getHanoi(int n) {
        Stack src = new Stack();
        Stack mid = new Stack();
        Stack dest = new Stack();
        return compute(n,src,mid,dest);
    }

    /**
     *
     * @param n  代表汉诺塔阶数
     * @param src 左边的柱子
     * @param mid 中间的柱子
     * @param dest 右边的柱子
     * @return 返回最少移动次数
     */
    private int compute(int n, Stack src, Stack mid, Stack dest) {
        if(n == 1) {
            return 1;
        }else {
            //先将前面n-1个圆盘移到中间的柱子上
           int result = compute(n-1,src,dest,mid);
           //再将最大的圆盘从左边移到右边的柱子上
           result++;
           //最后将中间柱子上的n-1个圆盘移到右边的柱子上
           result = result + compute(n-1,mid,src,dest);
           return result;
        }
    }

解法2:动态规划

由前面的分析,我们知道n阶汉诺塔的函数表达式为f(n)=f(n-1)+1+f(n-1),由此,我们可以直接复用建立状态转移方程f(n)=f(n-1)+1+f(n-1)

PS:使用动态规划算法时,状态转移方程有几个变量,我们就建立几维数组来存储中间结果

代码实现

 /**
     *
     * @param n 代表汉诺塔阶数
     * @return 返回最少移动次数
     */
    public int getHanoi(int n) {
        if(n == 1) {
            return 1;
        }
        int[] data = new int[n];
        data[0] = 1;
        for(int i = 1; i < n; i++){
            data[i] = data[i-1] + 1 + data[i-1];
        }
        return data[n-1];
    }

  • 10
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值