问题:
有一个100层高的楼,如果一个鸡蛋从n层掉下来或者n层以上,鸡蛋就会碎掉。已知,现在有两个鸡蛋,找到满足条件的n,使在最坏情况下,丢鸡蛋的次数最少。原题链接可以转到wiki:点击打开链接
很明显,不管egg1怎么丢,egg2肯定得线性得丢。
我们假设egg1每次丢10层,即按10f, 20f, 30f, 40f, 50f, 60f, 70f, 80f, 90f, 100f。
则,如果egg1在10f碎了,我们就不得不用egg2从1f按线性试了,此时最坏的情况是n=9,则总共丢了10次。
如果egg1在100f碎了,我们就不得不用egg2从90f按线性试了,此时最坏的情况是n=99,则总共丢了19次。
但是题目的要求是在最坏情况下丢的鸡蛋次数最少。也就是我们需要在最坏和最好做一下load balance。从上面的举例我们可以发现,越靠后试的次数越多,这是我们对每次丢的层数做了一个等价划分,每次多的都是egg1丢的次数,此时我们只能减少egg2丢的次数,已达到丢的总次数是相同的,很显然,每当egg1多丢一次的时候,egg2就少丢一次。
比如,假设第一次从x层丢下,如果此时n=x-1,显然我们需要试1+(x-1) = x次。
我们现有要分析第二次从那一层丢下,因为egg1比第一次多丢了一次,所以egg2在最坏情况下应该少丢一次,则第二次丢的楼层数是x-1
以此递推则,x + (x-1) + (x-2) + ...+ 1 >= 100,解之得x = 14;
则此时的顺序为:
14f, 27f, 39f, 50f, 60f, 69f, 77f, 84f, 90f, 95f, 99f, 100f
可以显式的试一下,最坏情况是不会超过14的,或者基本都是14次。
把问题再次扩展,如果是n个鸡蛋,k层楼?wiki中有关于这个解答,用动态规划。Wiki Egg Dropping Puzzle,其状态转移方程为:
W(n,k) = 1 + min{max(W(n − 1, x − 1), W(n,k − x)): x = 1, 2, ..., k } 并且初始化条件W(n,1)=1, W(1,k)=k
解释下这个状态转移方程,当我们在x层做实验的时候,我们有两种可能:
1)鸡蛋碎了,则我们就需要递归的处理:x-1 层,n-1个鸡蛋,也就是W(n-1, x-1)
2) 鸡蛋没碎,则我们局需要递归额处理:k-x 层,n个鸡蛋,也就是W(n, k-x)
因为题目要求是在最坏的情况下,所以求上面两个的max。但是要求最坏情况下的最小值,所以需要求x在1到k直接的最小值。
接下来,动态规划的代码就比较容易写了,如下是我自己写的一个:
public int eggDrop(int n, int m) {//n eggs, m floors.
int[][] dp = new int[n+1][m+1];
for (int i = 0; i < dp.length; i++) {
dp[i][1] = 1;
}
for (int i = 0; i < dp[0].length; i++) {
dp[1][i] = i;
}
for (int i = 2; i < dp.length; i++) {
for (int j = 2; j < dp[i].length; j++) {
dp[i][j] = Integer.MAX_VALUE;
for (int k = 1; k <= j; k++) {
int ret = 1 + Math.max(dp[i-1][k-1], dp[i][j-k]);
if (ret < dp[i][j]) {
dp[i][j] = ret;
}
}
}
}
return dp[n][m];
}
用计算机解法问题的好处就是我们可以试,我们可以把很多情况罗列出来,然后取最优解!