原題:
有2個雞蛋,從100層樓上往下扔,以此來測試雞蛋的硬度。比如雞蛋在第9層沒有摔碎,在第10層摔碎了,那么雞蛋不會摔碎的臨界點就是9層。
問:如何用最少的嘗試次數,測試出雞蛋不會摔碎的臨界點?
注意:只有兩個雞蛋。第一個雞蛋碎了,第二個雞蛋只能挨個樓層測試了。
動態規划解法:
//height為樓層數 const int maxHeight = 100; int dp[maxHeight + 5] = { 0 }; for (int height = 1; height <= maxHeight; height++) { dp[height] = height;//最土的方法,只用第一個雞蛋從1層開始往上試 for (int mid_h = 2; mid_h <= height; mid_h++) //第一個雞蛋從mid_h開始丟 { // mid_h-1 第一個雞蛋碎了,第二個雞蛋只能挨個試mid_h-1次; // dp[height-mid_h] 第一個雞蛋沒碎,兩個雞蛋剩下只需測dp[height-mid_h]次 dp[height] = min(dp[height], 1 + max(mid_h - 1, dp[height - mid_h])); //取max之后的min,則是最壞情況下的最優解法 } } // 動態規划完畢,看看結果 for (int height = 1; height <= maxHeight; height++) { printf("%4d %4d \n", height, dp[height]); }
數學解法:別人的
題目延伸:有M層樓 / N個雞蛋,要找到雞蛋摔不碎的臨界點,需要嘗試幾次?
圖非原創,結果如圖所示。
動態規划解法:
//樓層 雞蛋數 int dp[105][105] = { 0 }; int maxHeight = 100, maxEggs = 100; for (int height = 1; height <= maxHeight; height++) dp[height][1] = height; for (int eggs = 1; eggs <= maxEggs; eggs++) dp[1][eggs] = 1; for (int height = 2; height <= maxHeight; height++){ for (int eggs = 2; eggs <= maxEggs; eggs++){ int mid_h = 1;//第一個雞蛋丟第一層 //dp[mid_h-1][eggs-1]碎了 , dp[height-mid_h][eggs]沒碎。取max即最壞情況,再加上這一次的測試 dp[height][eggs] = 1 + max(dp[mid_h - 1][eggs - 1], dp[height - mid_h][eggs]); for (mid_h = 2; mid_h <= height; mid_h++) //第一個雞蛋丟第mid_h層 { //最壞情況的最小測試次數 dp[height][eggs] = min(dp[height][eggs], 1 + max(dp[mid_h - 1][eggs - 1], dp[height - mid_h][eggs])); } } } //動態規划完畢,看看結果 for (int height = 1; height <= 100; height++){ for (int eggs = 1; eggs <= 2; eggs++) { printf("%4d ", dp[height][eggs]); } printf("\n"); }