鸡蛋掉落

鸡蛋掉落

  • https://leetcode-cn.com/problems/super-egg-drop/
  • $dp[i][j]$表示$i-1$个鸡蛋,$j$层楼,最少的步数
  • $dp[i][j]=1+min{max{dp[i-1][k-1],dp[i][j-k]},1<=k<=j}$
  • 状态转移方程所采取的策略是:遍历第一次扔鸡蛋的楼层,然后选取其中需要扔鸡蛋次数最少的方案,而在每某层扔鸡蛋的最少次数是1+$max{dp[i-1][k-1],dp[i][j-k]$
  • 优化:
    • 可以看到对于固定的$j$,即固定的楼数,当k增大时$dp[i-1][k-1]$增大,$dp[i][j-k]$减小,因此这是一个交叉的单调函数,有最优点,为交叉点,可以用二分法求出交叉点复杂度从$O(n)$变成了$O(lgn)$
    • 当$k$固定,$j$增大时,$dp[i-1][k-1]$不变,$dp[i][j-k]$变大,因此交叉点一定是单调的,因此可以用一个变量记录交叉点 ,只需要单增检验就行了
  • 反向:$dp[i][j]$表示$i-1$个鸡蛋,$j$次扔鸡蛋,最大可以确定多少层楼
    • $dp[i][j]=dp[i][j-1]+dp[i-1][j-1]+1$
    • 此转移方程的策略是:站在$dp[i-1][j-1]+1$层扔,如果碎了,变成$dp[i-1][j-1]$,如果没碎,变成$dp[i][j-1]$,不管碎没碎,都可以保证检验$dp[i][j-1]+dp[i-1][j-1]+1$层楼
#include <iostream>
#include <string>
#include <vector>

using namespace std;
class Solution
{
public:
    int superEggDrop(int K, int N)
    {
        int dp[K][N+1];
        for (int i = 0; i < K;i++)
        {
            for (int j = 0; j < N + 1;j++)
            {
                if (i == 0)
                {
                    dp[i][j] = j;
                    continue;
                }
                if(j<=1)
                {
                    dp[i][j] = j;
                    continue;
                }
                int lo = 0, hi = j;
                int mid = (lo + hi) / 2;
                while(lo<hi)
                {

                    if (dp[i][mid] == dp[i - 1][j - mid - 1])
                    {
                        lo = mid;
                        break;
                    }
                    if(dp[i][mid]<dp[i-1][j-mid-1])
                    {
                        lo = mid + 1;
                    }
                    else if (dp[i][mid] > dp[i - 1][j - mid - 1])//一定成立
                    {
                        hi = mid;
                    }
                    mid = (lo + hi) / 2;
                }
               
                dp[i][j] = dp[i][lo] < dp[i - 1][j - lo] ? dp[i][lo] + 1 : dp[i - 1][j - lo]+1;
            }
            
        }
        return dp[K - 1][N];
    }
};
int main(){

    Solution x;
    std::cout<<x.superEggDrop(2, 6);
}



#include <iostream>
#include <string>
#include <vector>

using namespace std;
int max(int x,int y)
{
    return x > y ? x : y;
}
int min (int x,int y)
{
    return x < y ? x : y;
}
class Solution
{
public:
    int superEggDrop(int K, int N)
    {
        int dp[N+1];
        int dp2[N+1];
        for (int i = 0; i <=N;i++)
        {
           dp2[i]= dp[i] = i;
        }

        for (int k = 1; k < K;k++)
        {

       
            for (int i =2, j = 1; i <=N; i++)
            {

                while (max(dp[j - 1], dp2[i - j]) > max(dp[j], dp2[i - j - 1])&& j<i)
                {
                    j++;
                }
                dp[i] = max(dp[j - 1], dp2[i - j])+1;
                if(i==N)
                    for (int m = 0; m <=N;m++)
                        dp2[m] = dp[m];
            }
        }
        return dp[N];
    }
};



class Solution
{
public:
    int superEggDrop(int K, int N)
    {
        int dp[N];
        for (int i = 0; i < N;i++)
        {
            dp[i] = i + 1;
        }
           
        for (int i = 1; i < K;i++)
        {
            int temp1, temp2=dp[0];
            for (int j = 1; j <N;j++)
            {
                temp1 = dp[j];
                dp[j] = temp2 + dp[j-1] + 1;
                temp2 = temp1;
                if(dp[j]>N)
                    break;
               
            }
        }
        int i = 0;
        while(dp[i]<N)
        {
            i++;
        }
        return i+1;
    }
};

posted @ 2020-11-02 02:34  ArtistArthur  阅读(27)  评论(0)    收藏  举报