题⽬是这样:你⾯前有⼀栋从 1 到 N 共 N 层的楼,然后给你 K 个鸡蛋
( K ⾄少为 1)。现在确定这栋楼存在楼层 0 <= F <= N ,在这层楼将鸡
蛋扔下去,鸡蛋恰好没摔碎(⾼于 F 的楼层都会碎,低于 F 的楼层都不
会碎)。现在问你,最坏情况下,你⾄少要扔⼏次鸡蛋?
回溯法
public class ThrowAgg {
public static void main(String[] args) {
ThrowAgg ta = new ThrowAgg();
// System.out.println(ta.innerLoop(1, 2));
System.out.println(ta.innerLoop(2, 6));
// System.out.println(ta.innerLoop(3, 14));
}
/**
* 假设楼层只有6层,鸡蛋有2个,看最小次数是多少
* 然后如果有13层,鸡蛋有2个,先从第7扔,没碎。那么问题就变成了,楼层只有6层,有2个鸡蛋,求最小次数。
* 所以这就是动态规划先求子问题的由来。
* dp[i][j]: 最高楼层为j,鸡蛋有i个,最小扔dp[i][j]次,能够找出鸡蛋恰好不会破的楼层F。
*/
// 递归函数的意义:最高楼层为n,有k个鸡蛋,扔 innerLoop(k,n)次能够找出鸡蛋恰好不破的楼层f
public int innerLoop(int k, int n) {
if (k == 1) return n;
if (n == 0) return 0;
int res = Integer.MAX_VALUE;
for (int i = 1; i <= n; i++) {
res = Math.min(
res,
Math.max(
innerLoop(k - 1, i - 1),
innerLoop(k, n - i)
) + 1);
}
return res;
}
}
动态规划法
class ThrowAgg2 {
public static void main(String[] args) {
ThrowAgg2 ta = new ThrowAgg2();
System.out.println(ta.dynamic(2, 6));
}
/**
* 动态规划解决:遍历所有的状态,然后在选择中找到一个最好的。
*/
// dp[2][4]:最高楼层为4,有2个鸡蛋,最少扔 dp[2][4]次能够找出鸡蛋恰好不破的楼层f
public int dynamic(int k, int n) {
int[][] dp = new int[k + 1][n + 1];
for (int i = 1; i <= k; i++) {
for (int j = 0; j <= n; j++) {
// 因为比较最小值,所以把每个值先初始化成 最大值
dp[i][j] = Integer.MAX_VALUE;
if (i == 1) { //鸡蛋最少为1。base case:鸡蛋个数为1,那就全部都要试
dp[1][j] = j;
continue;
}
if (j == 0) { //base case:如果楼高为0,那一次都不用试
dp[i][0] = 0;
continue;
}
// 在碎和不碎里面找个层数最多的
for (int m = 1; m <= j; m++) {
dp[i][j] = Math.min(
dp[i][j],
Math.max(
dp[i - 1][m - 1], //
dp[i][j - m]
) + 1
);
}
}
}
return dp[k][n];
}
}