双蛋问题的递归解法

现在是疫情期间,被动裁员,呆在宿舍没事儿做,在YouTube上看见了李永乐老师的一个双蛋问题的视频,就是众所周知的动态规划问题,然后就做了一下。

1,问题描述:

有t层楼,n个鸡蛋,鸡蛋是相同的,临界楼层是指从某个楼层之上抛下来,都会碎,但从这个楼层之下抛下来,都不会碎。没有碎的鸡蛋可以重复使用。试假设能找到这个临界楼层需要抛投的最少次数。

2,问题分析,画表格。

假设横轴为鸡蛋数,纵轴为楼层数,值为最少抛投次数。填表格。

这里要求的是能找到临界值至少抛投的次数。一看就是动态规划,直接找递归式。

设M(t,n)为在从t层楼,n个蛋的情况下需要抛投的最少次数,情况有多少种呢。当然是t种,从每一层都抛出一个鸡蛋试一下。

现在就要得到这t个抛投实验中的最小抛投次数。设Mk(t,n)为从k(1<=k<=t)层楼抛下1个鸡蛋进行测试而得到的抛投数。这t种抛投有通用的递推模式:

假设在k层楼进行抛投,会产生两种情况:

碎了:问题规模变为:M(k-1, n-1)

没碎:问题规模变为:M(t-k, n)

则Mk(t,n) = max(M(k-1, n-1), M(t-k, n)) + 1,也就是求出这种情况下最大的抛投次数。

而M(t,n)= min(M1(t,n), M2(t,n), M3(t,n) ...... Mk(t,n))

3,代码实验:

public class Egg {
    private int t;//t层楼
    private int n;//n个鸡蛋
    private int[][] m;//最优解,在(i(楼层),j(鸡蛋))时候的最优解。最优解是指,一定能找到临界楼层情况下的最少抛投次数。

    private Egg(int t, int n) {
        this.t = t;
        this.n = n;
        this.m = new int[t + 1][n + 1];// 舍弃零行零列的数据不要
        for (int[] ints : this.m) {
            for (int anInt : ints) {
                anInt = Integer.MAX_VALUE;// 全部初始化为最大值
            }
        }
        // 填充1行1列的简单数据
        for (int i = 1; i < t + 1; i++) {
            m[i][1] = i;//一层楼的话,至少试一次
        }
        for (int j = 1; j < n + 1; j++) {
            m[1][j] = 1;//一个鸡蛋的话,要试的次数为楼层数
        }
    }

    public int result() {//填充大于1行1列的空格
        for (int tt = 2; tt < t + 1; tt++) {//从第二层楼开始
            for (int nn = 2; nn < n + 1; nn++) {//从有两个鸡蛋开始
                int min = Integer.MAX_VALUE;
                for (int k = 1; k < t + 1 && tt > k; k++) {//第一次从k层楼抛切分
                    min = Math.min(min, Math.max(m[tt - k][nn], m[k - 1][nn - 1]) + 1);
                    // 如果失败,问题变为m[k-1][n-1],如果成功,问题变为m[t-k][n],现在每一层都切分一次,然后找到每一层切分需要的最大值。
                    // 然后从每层楼中取最小值,这里要注意我们求的是什么:保证一定能找到临界楼层的最小抛投次数。
                }
                m[tt][nn] = min;
            }
        }
        return m[t][n];
    }


    public static void main(String[] args) {

        for (int i = 1; i < 26; i++) {
            System.out.print(i + " floors\t");
            for (int j = 1; j < 11; j++) {
                System.out.print(new Egg(i, j).result() + "\t");
            }
            System.out.println();
        }
    }
}

4,结果验证:

正确答案为:

是相同的。答案正确

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值