高楼扔玻璃球问题

题目描述:

腾讯大厦有100层,你手里有两颗玻璃球。当你拿着玻璃球在某一层往下扔的时候,一定会有两个结果,玻璃球碎了或者没碎。

大厦有个临界楼层。低于它的楼层,往下扔玻璃球,玻璃球不会碎,等于或高于它的楼层,扔下玻璃球,玻璃球一定会碎。玻璃球碎了就不能再扔。

现在让你设计一种方式,使得在该方式下,最坏的情况扔的次数比其他任何方式最坏的次数都少。也就是设计一种最有效的方式。


两种思路解法:


分区思想:

♦玻璃球属于消耗品,一旦第一颗球摔碎了,那么就只会剩下最后一颗球来去测量临界值,假设我们从第一层开始扔,那么最坏情况是从第一层试验到九十九层(最后一层就不用在测了),那么也需要试验99次

次,因此我们不应该从第一层开始试验

♦假设我们从任意一层楼x层将玻璃球扔下去,球分碎和不碎两种情况,如果碎了,那么就从该层楼继续往上扔,最坏需要(100-x-1(最后一层楼不用测临界值就是它了)+1(第一颗玻璃球碎的那一次))次,

如果没碎的话,那么继续把第一颗球从比x楼层高的y层扔,又分碎和没碎两种情况,知道第一颗球碎了,再讲第二颗球从上一次扔第一颗球没碎的楼层开始,逐层往上扔,从而找到临界值

因此x,y的划分仍然需要我们讲究区域的划分

♦现在我们自己进行区间划分,假设我们将区建设为10,那么1到100层就需要划分10个区间,从最底层的区间开始逐个往上试验(每次都试该区间的最高层)一旦球在

哪一个区间碎了,那么就可以锁定临界值在此区间,因此最坏情况为9+9(前九个区间+最后一个区间的前九层),

但是这样做的话,仍然不是很合理?因为按照概率来算:越往高层,球碎的概率就越大,也就是说前面区间划分的不是很均匀,越往高层时,高层区间大小应该越来越小,而底层区间由于球碎的可能性

较小,所以应该尽可能让区间大小变大,这样最终的结果:区间个数+最后一层区间的大小的值就会尽可能的变小

我们采取逐步递减的方式,让最后一个区间只有一层,那么倒数第二个区间就只有两层,就转变成了1+2+...+x=100,解得:x约等于14,1+...+14=105,因此最大实验次数不应该超过14

♦以此类推,若楼层为n层,那么问题就转变为从1+...+x=n,解得的x即为最坏的次数


动态规划思想:

class Main{
    public static void main(String[] args) {
        int building = 100;
        //初始化,考虑数组边界0
        int[] dp = new int[building+1];
        //根据上面的思路,假设每一层都有碎的可能性,遍历求解,假设第i层球碎
        for (int i = 2;i <=building;i++){
            //最坏次数里面最优解法,假设为building,当然building-1更贴切,但并不影响程序结果
            int Min = building;//每一次i层碎的情况引发后续的 最小次数不同,需要重置Min的次数
            //第二层遍历,假设在第j层球碎
            for (int j = 1;j < i;j++){
                //那么用到的最大次数,要么从i层开始从上往下数到j层(i-j)+1(原来的第一次在i层碎的那一次),
                // 要么从第1层开始到j层,即用了j-1+1=j次
                int Max = dp[i-j]+1;
                //因为要考虑最坏情况,所以要取最大值
                if (Max < j){
                    Max = j;
                }
                //Min当然要取最小值了
                if (Max < Min){
                    Min = Max;
                }
            }
            //第一次在i层碎的之后,后续个种情况的最小次数
            dp[i] = Min;
        }
        //遍历各种在i层碎的可能情况
        System.out.println(dp[building]);
    }
}
原文地址:https://www.cnblogs.com/hetaoyuan/p/11284546.html