题目链接:https://leetcode-cn.com/problems/super-egg-drop/
题目大意:
有K个鸡蛋,N层楼。第F层楼及以下鸡蛋扔下去不会碎,以上扔下去会碎,如果扔下去没碎还能继续用,否则就没了。问最少多少次能够保证无论F是哪一层都能测出来。
题目思路:
看了半天没看出是DP…首先可以发现一个事情,如果只有一个鸡蛋,那么想试只能从一楼慢慢往上了,否则鸡蛋碎了就凉了。如果有无数个鸡蛋,但是只有一楼,那么也当且仅当一次是需要的。这就是dp的预处理。
接下来咋办呢?可以这么考虑DP方程。如果现在有K个鸡蛋,N层楼,那么这个鸡蛋可能是从X层楼开始实验,那么接下来有两种情况:
- 鸡蛋碎了。那么鸡蛋变K-1个,但是可以发现F肯定小于X,所以接下来需要测试的楼层数就变成了X-1,那么接下来需要的次数就是dp[K-1][X-1]
- 鸡蛋没碎。那么鸡蛋还是K个,但是说明答案是当前或者以上楼层,只需要测试上面的楼层,需要测的数量变N-X,那么需要的次数就是dp[K][N-X]
然后就可以根据找个进行DP转移了,要么碎了要么没碎,因为要百分百能测出来,所以要取这俩中的最大值,不然大的那种情况发生了咋办,不就测不出来了么。但是可以发现,这个X还需要遍历,复杂度太高了,但是我们还能发现, m a x ( d p [ K − 1 ] [ X − 1 ] , d p [ K ] [ N − X ] ) max(dp[K-1][X-1],dp[K][N-X]) max(dp[K−1][X−1],dp[K][N−X])有一个牛逼的性质,那就是随着x的增大dp[K-1][X-1]非递减,dp[K][N-X]非递增,那么那个交点的位置就是要找的最小值,直接二分找到dp[K][N-X]大于dp[K-1][X-1]的最靠右的位置,因为我们要的是整数点,但是可能是小数,所以小数两头的整数都得试试,也就是试试这个二分出来的点x和这个点+1,取最小值。
太久没写代码,能力退化的非常严重。。(本来就菜),最近状态也有点不好需要加油了!
以下是代码:
class Solution {
public:
int dp[105][10005];
int superEggDrop(int K, int N) {
memset(dp,0,sizeof(dp));
for(int i=1;i<=N;i++)dp[1][i]=i;
for(int i=1;i<=K;i++)dp[i][1]=1;
for(int i=2;i<=K;i++){
for(int j=2;j<=N;j++){
int l=1,r=j,ans=1;
while(l<=r){
int mid=(l+r)>>1;
if(dp[i][j-mid]>dp[i-1][mid-1]){
ans=mid;
l=mid+1;
}
else r=mid-1;
}
dp[i][j]=1+min(max(dp[i][j-ans],dp[i-1][ans-1]),max(dp[i][j-ans-1],dp[i-1][ans]));
}
}
return dp[K][N];
}
};