鸡蛋的硬度

鸡蛋的硬度

先想一个简单问题:只有两个鸡蛋的问题

  • 两个软硬一样但未知的鸡蛋。有座100层的建筑,要你⽤用这两个鸡蛋确定 哪一层是鸡蛋可以安全落下的最⾼高位置。可以摔碎两个鸡蛋。

  • 这是典型的动态规划问题。假设f[n]表示从n层楼找到摔鸡蛋不碎安全位置的最少判断次数。假设第⼀个鸡蛋第一次从第i层扔下,如果碎了了,就剩⼀个鸡蛋,为确定下⾯面楼层中的安全位置,必须从第⼀层挨着试,还需 要i−1次;如果不碎的话,上面还有n−i层,剩下两个鸡蛋,还需要f[n−i]次 (子问题,n层楼的上n-i层需要的最少判断次数和n-i层楼需要的最少判断 次数其实是⼀样的)。因此,最坏情况下还需要判断max(i-1,f[n-i])次。

  • 状态转移方程:
    f [ n ] = m i n 1 + m a x ( i − 1 , f [ n − i ] ) ∣ i = 1 … n f[n]=min1+max(i−1,f[n−i])|i=1…n f[n]=min1+max(i1,f[ni])i=1n

  • 初始条件: f[0]=0(或f[1]=1)

推广成n层楼,m个鸡蛋

  • 还是动态规划。假设f[n,m]表示n层楼、m个鸡蛋时找到摔鸡 蛋不碎的最少判断次数。则⼀个鸡蛋从第i层扔下,如果碎了,还剩m-1个鸡蛋,为确定下面楼层中的安全位置,还需要f[i−1,m−1]次(子问题);不碎的话,上面还有n-i层,还 需要f[n−i,m]次(子问题,n层楼的上的n-i层需要的最少判断次数和n-i层楼需要的最少判断次数其实是⼀样的)。

  • 状态转移方程:
    f [ n , m ] = m i n 1 + m a x ( f [ i − 1 , m − 1 ] , f [ n − i , m ] ) ∣ i = 1.. n f[n,m]=min1+max(f[i−1,m−1],f[n−i,m])|i=1..n f[n,m]=min1+max(f[i1,m1],f[ni,m])i1..n

  • 初始条件:f[i,0]=0(或f[i,1]=i),对所有i

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N = 110, M = 12;

/*
f[i][j] : 用j个鸡蛋,测量i层高楼,最优策略下最大测量次数
状态转移 : 
1. 不用第j个鸡蛋 : f[i][j] = f[i][j - 1];
2. 用第j个鸡蛋 : 
    测量第k层楼,第j个鸡蛋是否碎
    1) 没碎:f[i][j] = f[k - 1][j] + 1;
    2) 碎:f[i][j] = f[i - k][j - 1] + 1;
*/
int f[N][M]; // 

int main(){
    int n, m;
    while(cin >> n >> m){
        // scanf("%d%d", &n, &m);
        memset(f, 0, sizeof f);
    
        for(int i = 1; i <= m; ++i) f[1][i] = 1;
        for(int i = 1; i <= n; ++i) f[i][1] = i;
        
        for(int i = 2; i <= n; ++i){
            for(int j = 2; j <= m; ++j){
                f[i][j] = f[i][j - 1];
                for(int k = 1; k <= i; ++k){
                    f[i][j] = min(f[i][j], max(f[k - 1][j - 1], f[i - k][j]) + 1);
                }
            }
        }
        
        printf("%d\n", f[n][m]);
    }
    
    return 0;
}
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N = 110, M = 12;

/*
f[i][j] : 用j个鸡蛋,测量i次,最大的测量区间
状态转移 :
枚举扔鸡蛋的楼层k,类似dp1,
没碎测k楼以上,碎了测k楼以下,
那么能测的最大高度就是上下两部分加上第k层楼这一层
    f[i][j] = f[i - 1][j] + f[i - 1][j - 1] + 1;
*/
int f[N][M]; // 

int main(){
    int n, m;
    while(cin >> n >> m){
        for(int i = 1; i <= n; ++i){
            for(int j = 1; j <= m; ++j){
                f[i][j] = f[i - 1][j] + f[i - 1][j - 1] + 1;
            }
            if(f[i][m] >= n){
                printf("%d\n", i);
                break;
            }
        }
    }
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值