ural1223 鹰蛋(dp优化)

题意:

有一堆共 M 个鹰蛋,一位教授想研究这些鹰蛋的坚硬度 E。他是通过不断 从一幢 N 层的楼上向下扔鹰蛋来确定 E 的。当鹰蛋从第 E 层楼及以下楼层落下 时是不会碎的,但从第(E+1)层楼及以上楼层向下落时会摔碎。如果鹰蛋未摔 碎,还可以继续使用;但如果鹰蛋全碎了却仍未确定E,这显然是一个失败的实 验。教授希望实验是成功的。 例如:若鹰蛋从第 1 层楼落下即摔碎,E=0;若鹰蛋从第N层楼落下仍未碎,
E=N。 这里假设所有的鹰蛋都具有相同的坚硬度。给定鹰蛋个数 M 与楼层数 N。
要求最坏情况下确定E 所需要的最少次数。

tip:

dp[i][j]表示用 i 个蛋在 j 层楼上最坏情况下确定答案所需要的最少次数
若蛋在w层碎了,那么答案在w-1那些层里面,(w是二分来的,因为二分是理论上快的),fdp【i-1】,【w-1】+1
若没碎,答案在w到n的那些层里面,dp【i】【j-w】)+1
两个中取较大的值,因为是最坏条件下,所以这两种都可能发生的话选更不好的,
循环ijw O(n^3)
优化:
首先如果蛋很多,多到够二分,那么结果一定是二分的值
2.
这里写图片描述
如图可以看出best的位置是dp最优选择,所以二分找dp【i-1】【w】 = dp[i][j-w]的w值。。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 1100;
const int inf = 1e9+7;
int dp[2][maxn];
int egg,n;
void bi_Se(int f,int i,int j){
    int l = 1 , r = j;
    while(l <= r){
        int mid = (l+r)/2;
        if(dp[f^1][mid-1] > dp[f][j-mid]){
            r = mid-1;
            dp[f][j] = min(dp[f][j],dp[f^1][mid-1]+1);
        }
        else if(dp[f^1][mid-1] == dp[f][j-mid]){
            dp[f][j] = dp[f^1][mid-1]+1;
            return ;
        }
        else{
            l = mid+1;
            dp[f][j] = min(dp[f][j],dp[f][j-mid]+1);
        }
    }
}
void sov(){
    for(int i = 0; i <= n ; i++)    dp[1][i] = i;
    int now = 1,pre =0;
    for(int i = 2; i <= egg ; i++){
        swap(now,pre);
        dp[now][0] = 0;
        for(int j = 1; j <= n ; j++){
            dp[now][j] = inf;
            bi_Se(now,i,j);
        }
    }
    printf("%d\n",dp[now][n]);
}
int main(){
    while(~scanf("%d%d",&egg,&n) && (egg || n)){
        int tmp = floor(log(n)/log(2)+1);
        if(egg >=  tmp) printf("%d\n",tmp);
        else    sov();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值