算法(动态规划二)
问题
腾讯大厦有39层,你手里有两颗一抹一眼的玻璃珠。当你拿着玻璃珠在某一层往下扔的时候,一定会有两个结果,玻璃珠碎了或者没碎。大厦有个临界楼层。低于它的楼层,往下扔玻璃珠,玻璃珠不会碎,等于或高于它的楼层,扔下玻璃珠,玻璃珠一定会碎。玻璃珠碎了就不能再扔。现在让你设计一种方式,使得在该方式下,最坏的情况扔的次数比其他任何方式最坏的次数都少。也就是设计一种最有效的方式。
分析
咱们先不论腾讯大厦具体为多少层。假设大楼为 N 层,那么 F(N) 为 N 层大厦最坏情况的最小值。
先假设一下,在第 10 层进行了抛球:
碎了,那么寻找临界楼层,最坏情况下只需要从 1 - 9 逐一遍历,也就是 10 次。
没碎,那么寻找临界楼层,相当于转换为 F(N - 10) + 1 。其中 1 为本次。
也就是说,第 10 层的最坏情况为 max(10, F(N - 10) + 1)。
那么 F(N) = min{ max(1, F(N - 1) + 1), max(2, F(N - 2) + 1), max(3, F(N - 3) + 1), …… , max(N - 1, F(1) + 1)}
有了以上这个状态转移方程,就可以采用动态规划将其实现。
<?php $height = 39; echo getMinTimes($height); function getMinTimes($value) { $minTimes = []; $minTimes[0] = 0; // 如果只有0层的话最大次数为0 $minTimes[1] = 1; // 如果只有1层的话最大次数为1 // 初始化参数 for($levelOne = 2; $levelOne <= $value; $levelOne ++) { $min = $levelOne; for($levelTwo = 1; $levelTwo < $levelOne; $levelTwo ++) { $tmp = max($levelTwo, $minTimes[$levelOne - $levelTwo] + 1); // echo $tmp; // echo " "; if ($tmp < $min) { $min = $tmp; } // echo $min; // echo "=== "; } // echo PHP_EOL; $minTimes[$levelOne] = $min; // echo $minTimes[$levelOne]; } return $minTimes[$value]; } ?>