原题:
有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 ", 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(" "); }