C++ 动态规划 鸡蛋掉落

这篇博客讨论了一个经典的计算机科学问题——鸡蛋掉落,目标是确定在给定数量的鸡蛋和楼层的情况下,找出鸡蛋从哪一层落下会破裂的最小操作次数。文章介绍了三种不同的动态规划解决方案,包括传统的二维DP、高效的二维DP以及一维DP优化方法,通过递归和迭代的方式逐步减少操作次数,以达到最优化的结果。
摘要由CSDN通过智能技术生成

题目

给你 k 枚相同的鸡蛋,并可以使用一栋从第 1 层到第 n 层共有 n 层楼的建筑。

已知存在楼层 f ,满足 0 <= f <= n ,任何从 高于 f 的楼层落下的鸡蛋都会碎,从 f 楼层或比它低的楼层落下的鸡蛋都不会破。

每次操作,你可以取一枚没有碎的鸡蛋并把它从任一楼层 x 扔下(满足 1 <= x <= n)。如果鸡蛋碎了,你就不能再次使用它。如果某枚鸡蛋扔下后没有摔碎,则可以在之后的操作中 重复使用 这枚鸡蛋。

请你计算并返回要确定 f 确切的值 的 最小操作次数 是多少?

示例 1:

输入:k = 1, n = 2
输出:2
解释:
鸡蛋从 1 楼掉落。如果它碎了,肯定能得出 f = 0 。
否则,鸡蛋从 2 楼掉落。如果它碎了,肯定能得出 f = 1 。
如果它没碎,那么肯定能得出 f = 2 。
因此,在最坏的情况下我们需要移动 2 次以确定 f 是多少。

示例 2:

输入:k = 2, n = 6
输出:3

示例 3:

输入:k = 3, n = 14
输出:4

dp 二分思路

dp [ k ][ n ] k表示鸡蛋数,n表示搜索楼层区间

class Solution {
public:
    int **dp;
    int superEggDrop(int k, int n) {
        dp=new int*[k+1];
        for(int i=0;i<k+1;i++)
        {
            dp[i]=new int[n+1];
            memset(dp[i],0,(n+1)*sizeof(int));
        }
        return EggDP(k,n);
       
    }
     int EggDP(int k,int n)     //k表示鸡蛋数,n表示搜索楼层区间
    {   
        if(k==1)            //鸡蛋数为1时只能线性扫描楼层
            return n;
        if(n==0)
            return 0;
        
        if(dp[k][n]!=0)
            return dp[k][n]; 
        int res=INT_MAX;
        int left=1;
        int right=n;
        while(left<=right)
        {
            int mid=(left+right)/2;
            int broken=EggDP(k-1,mid-1);   //碎了
            int not_broken=EggDP(k,n-mid);  //没碎
            if(broken >not_broken )    //broken 最坏情况
            {
                right=mid-1;
                res=min(res,broken+1);   //比较的两种情况取最坏情况
            }
            else
            {
                left=mid+1;
                res=min(res,not_broken+1);
            }
        }
        dp[k][n]=res;
        return res;
    }
};

高效dp

class Solution {
public:
    int **dp;
    int superEggDrop(int k, int n) {
        dp=new int*[k+1];
        for(int i=0;i<k+1;i++)
        {
            dp[i]=new int[n+1];
            memset(dp[i],0,(n+1)*sizeof(int));
        }
        int m=0;
        //dp[k][m],表示k个鸡蛋,最多允许的扔鸡蛋次数m,能确定的最高楼层数
        while(dp[k][m]<n)
        {
            m++;
            for(int i=1;i<=k;i++)
            {
                dp[i][m]=dp[i][m-1]+dp[i-1][m-1]+1;
                //1.dp[i][m-1]代表鸡蛋没碎,次数-1,往楼上找的层数
                //2.dp[i-1][m-1]代表鸡蛋碎了,次数-1,往楼下找的层数
                //以上两个+1就是dp[i][m]找到的总层数
            }
        }
        return m;     
    }   
};

终极版本,一维dp

class Solution {
public:
    int superEggDrop(int k, int n) {
        int *dp=new int[k+1];
        memset(dp,0,(k+1)*sizeof(int));
        int m=0;
        while(dp[k]<n)
        {
            m++;
            int pre=0;
            for(int i=1;i<=k;i++)
            {
                int temp=dp[i];
                dp[i]=dp[i]+pre+1;
                pre=temp;
            }
        }
        return m;     
    }   
};
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值