动态规划优化问题-5

例四:扔鸡蛋问题

​ 定义鸡蛋的硬度为 k,则代表鸡蛋最高从 k 楼扔下来不会碎掉,现在给你 n 个硬度相同的鸡蛋,楼高为 m,问最坏情况下最少测多少次,可以测出鸡蛋的硬度。

​ 我们假设有2个鸡蛋,100层楼。那么我们应该如何扔在最坏情况下测的次数最少呢?

1.二分法:刚开始我傻傻的以为是二分法,第一个鸡蛋在第50层扔,但是如果一个鸡蛋在第50层碎了,那么第二个鸡蛋只能从第1层扔直到第49层,才能测出鸡蛋的硬度(在最坏情况为49层时),这样最坏情况下需要测50次

2.平方根法:我们继续优化,我们每10层测一次,第10层若碎了,第二个鸡蛋就从1层测到9层。若没碎继续测第20层…以此类推,最坏情况是第99层时,这时我们需要测10 + 9 = 19次

3.假设法:方法二一定是最优解吗?我们可以假设一下,设2个鸡蛋100层楼在最坏情况下最多测x次,那么第一个鸡蛋应该放在第x层最合适(如果第一个鸡蛋放在是x + i层,如果碎了最坏情况下最多测x + i次,比x次多;如果第一个鸡蛋放在x - i层,如果没碎的话,由于x - i比x小,所以它剩余测的次数一定 >= x)

​ 因此,我们第一次放在x层(碎了话最多测x次,没碎的话第二次放在2 * x - 1层,碎的话最多测x次,没碎的话第三次放在3 * x - 3层,碎的话最多测x次,没碎的话第四次放在4 * x - 6层…依次类推),我们只要保证x + (x - 1) + (x - 2) … + 1 >= 100即可,这样解出最优答案为14

​ 好了,以上是推理,我们可以用dp的方法来求出正确的答案。我们可以假设dp[i][j]代表i个鸡蛋j层楼最少测多少次。这样我们可以得到:

初始化:
dp[1][j] = k (1 <= j <= m)	//一个鸡蛋j层楼最坏情况下最少需要测j次
dp[i][1] = 1 (1 <= i <= n)  //i个鸡蛋1层楼最坏情况下最少需要测1次

这样我们可以得到dp转移式:
dp[i][m] = min(max(dp[i - 1][j - 1], dp[i][m - j]))  (1 <= j <= m)

​ 那么,当n范围为1e2,m范围为1e9的时候,我们怎么办呢?

​ 数组肯定开不下那么大,而且上面算法的时间复杂度为O(n(m^2)),会直接爆掉的。这时我们就可以进行重新定义状态信息来优化算法。

​ 我们可以假设dp[i][j]代表i个鸡蛋测j次最多能测多少层楼。这样我们可以得到:

//初始化:
dp[1][j] = j + 1	//一个鸡蛋测j次最多可以测j + 1层楼
dp[i][1] = 2  		//i个鸡蛋测1次最多可以测2层楼

//当第j次测试碎了,那么dp[i][j] = dp[i - 1][j - 1];
//当第j次测试没碎,那么dp[i][j] = dp[i][j - 1];
//因为第j次测试只有上述两种情况,所以我们可以得到dp转移式:
dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];

我们只要找第一个dp[n][j]大于m的j即是正确答案

​ 最后上AC代码:

#include <stdio.h>
#define ll long long

ll dp[35][100005] = {0};

int main () {
    ll n, m;
    scanf("%lld%lld", &n, &m);
    if (n == 1) {
        printf("%lld\n", m);
    } else {
        for (int i = 1; i <= 100000; i++) {
            dp[1][i] = i + 1;
        }
        for (int i = 1; i <= n; i++) {
            dp[i][1] = 2;
        }
        for (int i = 2; i <= n; i++) {
            for (int j = 2; j <= 100000; j++) {
                dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];
            }
        }
        for (int j = 1; j <= 100000; j++) {
            if (dp[n][j] >= m) {
                printf("%d\n", j);
                break;
            }
        }
    }
    return 0;
}

转载请注明出处!!!

如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢

猜你喜欢

转载自blog.csdn.net/Ivan_zcy/article/details/86561704
今日推荐