鸡蛋掉落
问题
你将获得K个鸡蛋,并可以使用一栋从1到N共N层楼的建筑。每一个蛋的功能都是一样的,如果一个鸡蛋碎了,你就不能再把它掉下去了。你知道存在楼层F,满足0<=F<=N任何从高于F的楼层落下的鸡蛋都会碎,从F楼层或者比它低的楼层落下的鸡蛋不会破。每次移动,你可以取一个鸡蛋(如果你有完整的鸡蛋)并把它从任一楼层X扔下(满足1<=X<=N)。你的目标是确切地知道F的值是多少。无论F的初始值如何,你确定F的值的最小移动次数是多少?
解决办法
运用动态规划原理,相当于打表格。
public int superEggDrop(int K, int N) {
//需要 0 这个状态的值,这里 0 层楼和 0 个鸡蛋是需要考虑进去的,它们的值会被后来的值所参考,并且也比较容易得到
int[][] dp =new int[N+1][K+1];
//dp[N]表示是楼层期间
for(int i=1;i<=N;i++)
for(int j=1;j<=K;j++)
{
dp[i][j]=i;//初始化i或者很大的数,便于后面计算。
}
//当楼层为0时,F为0
for(int i=0;i<K+1;i++)
dp[0][i]=0;
//当鸡蛋个数为0时,F=0
for(int i=0;i<N+1;i++)
dp[i][0]=0;
//当一个鸡蛋的时候,F为给的楼层数
for(int i=1;i<=N;i++)
{
dp[i][1]=i;
}
//当楼层为1时,其鸡蛋为0是F=0,鸡蛋大于等于1时F=1;
for(int i=1;i<=K;i++)
dp[1][i]=1;
//当i=2,j=2时
for(int i=2;i<=N;i++)
for(int j=2;j<=K;j++)
for(int k=1;k<=i;k++)
//当从k层落下的时候,如果鸡蛋打碎,则从k-1层考虑,此时鸡蛋为j-1
//当从k层落下 的时候,如果鸡蛋没有打碎,则从i-k层考虑,此时鸡蛋为j
//找到这两种情况的最大值,与原来的进行比较,找其最小值
//因为在k层已经做了一次实验,则实验次数要加1
dp[i][j]=Math.min(dp[i][j],Math.max(dp[k-1][j-1],dp[i-k][j])+1);
//优化
//当i=2,j=2时
for(int i=2;i<=N;i++)
for(int j=2;j<=K;j++)
//找到一个K使得dp[i-k][j]与dp[k-i][j-1]中的最大值
{
int left=1;
int right=i;
while(left<=right)
{
int mid=(left+right)/2;
if(dp[i-mid][j]>dp[mid-1][j-1])
left=mid+1;
else
right=mid-1;
}
dp[i][j]=Math.min(dp[i][j],Math.max(dp[left-1][j-1],dp[i-left][j])+1);
}
return dp[N][K];
}