一本通1300:鸡蛋的硬度

1300:鸡蛋的硬度


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 1055     通过数: 705 

【题目描述】

最近XX公司举办了一个奇怪的比赛:鸡蛋硬度之王争霸赛。参赛者是来自世界各地的母鸡,比赛的内容是看谁下的蛋最硬,更奇怪的是XX公司并不使用什么精密仪器来测量蛋的硬度,他们采用了一种最老土的办法--从高度扔鸡蛋--来测试鸡蛋的硬度,如果一次母鸡下的蛋从高楼的第a层摔下来没摔破,但是从a+1层摔下来时摔破了,那么就说这只母鸡的鸡蛋的硬度是a。你当然可以找出各种理由说明这种方法不科学,比如同一只母鸡下的蛋硬度可能不一样等等,但是这不影响XX公司的争霸赛,因为他们只是为了吸引大家的眼球,一个个鸡蛋从100 层的高楼上掉下来的时候,这情景还是能吸引很多人驻足观看的,当然,XX公司也绝不会忘记在高楼上挂一条幅,写上“XX公司”的字样--这比赛不过是XX 公司的一个另类广告而已。

勤于思考的小A总是能从一件事情中发现一个数学问题,这件事也不例外。“假如有很多同样硬度的鸡蛋,那么我可以用二分的办法用最少的次数测出鸡蛋的硬度”,小A对自己的这个结论感到很满意,不过很快麻烦来了,“但是,假如我的鸡蛋不够用呢,比如我只有1个鸡蛋,那么我就不得不从第1层楼开始一层一层的扔,最坏情况下我要扔100次。如果有2个鸡蛋,那么就从2层楼开始的地方扔……等等,不对,好像应该从1/3的地方开始扔才对,嗯,好像也不一定啊……3个鸡蛋怎么办,4个,5个,更多呢……”,和往常一样,小A又陷入了一个思维僵局,与其说他是勤于思考,不如说他是喜欢自找麻烦。

好吧,既然麻烦来了,就得有人去解决,小A的麻烦就靠你来解决了:) 

【输入】

输入包括多组数据,每组数据一行,包含两个正整数n和m(1≤n≤100,1≤m≤10),其中n表示楼的高度,m表示你现在拥有的鸡蛋个数,这些鸡蛋硬度相同(即它们从同样高的地方掉下来要么都摔碎要么都不碎),并且小于等于n。你可以假定硬度为x的鸡蛋从高度小于等于x的地方摔无论如何都不会碎(没摔碎的鸡蛋可以继续使用),而只要从比x高的地方扔必然会碎。

对每组输入数据,你可以假定鸡蛋的硬度在0至n之间,即在n+1层扔鸡蛋一定会碎。 

【输出】

对于每一组输入,输出一个整数,表示使用最优策略在最坏情况下所需要的扔鸡蛋次数。

【输入样例】

100 1
100 2

【输出样例】

100
14

【分析】

这个题目有很多地方都有分析,我也看了好几个解答,但都说得不太明白(也许是我笨),我结合听的讲座和各家分析,加上自己的试验作以下分析。

这时的策略大体如下:第一,最简单的和种情况就是只有一只鸡蛋,那只能从一楼开始一层一层往上走,如果第一楼就破了,那硬度就是0,否则总能找到破与不破的两层。那意味着硬度为多少就得比硬度数多扔一次就好。如果题目给的楼层是100,那最坏的可能就是硬度为99,必须扔100次。(硬度不能为100,题目说了硬度小于n,也意味着从顶楼扔下,鸡蛋一定会碎,但这一次必须要扔)。第二,如果有两枚鸡蛋呢?那第一次就不用在第一楼扔,那在多少楼扔合适?答案是第14楼。那要是破了呢?说明硬度最大13,同时我们手里的鸡蛋也只有一枚了,那办法就只有一个了:从第一楼开始往上,根据刚才的经验,最多再扔13次就好(1-13楼全试,只有一枚鸡蛋,不能冒险哟)。那要是没破呢?又在哪扔呢?第27楼。要是破了,硬度在14-26之间,最多再试12次就可以了,加上之前14楼和27楼两次,共14次。要是没破,下一次选在39楼。同样要是破了,就从28开始往上走,最多走到第38楼,共14次,要是没破,就选50楼。。。。,以后每多一次间距就少一,均能保证14次能测出硬度。第三,为什么是14楼开始?10楼不行么?如果选10楼,要是破了,当然比刚才更快,那要是没破呢?下一次选多少楼?20?然后30、40、50、60、70、80、90?到了60己经扔了6次了,要是破了,最坏的情况是要再扔9次,在是没破又如何继续?明显不是最佳策略。那为什么是14次?按照刚才的策略1+2+3+...+14=105超过100了,说明14次一定能测出结果。第四,要是鸡蛋有更多个呢?比如有三个,第一次可以考虑对分:第50楼,要是不破,再二分,75楼.....,要是破了,就相当于两个鸡蛋测50楼,1+2+3+...+10=55,再有10次就可以搞定了。如果有四个鸡蛋呢?两次就把范围缩小到25楼了,1+2+3+...+7=28,共需9次。那要是鸡蛋无限呢,最多也是全二分,2^7=128,这个就是最效率的了,换句话说,对100层楼而言,多于7个鸡蛋也没用。第五,如果有m个鸡蛋n层楼呢?我们用f[n][m]记最少的次数。那可以枚举从第k层楼扔下,有两种情况:(1)鸡蛋破了,那硬度在1-k-1之间,我们得用余下的m-1个鸡蛋测试k-1层楼,这时f[n][m]=f[k-1][m-1],(2)鸡蛋没破。那再测余下的k~n层楼就好,这时f[n][m]=f[n-k][m],题目要求是最坏的情况,故需要取这两种情况的最大值。故f[n][m]=max(f[k-1][m-1],f[n-k][m])+1。对所有的k的取值得到若干个f[n][m],这个我们可以选择k值,故把这些值再取最小值。f[n][m]=min(f[n][m],max(f[k-1][m-1],f[n-k][m])+1),这就是帅气的状态转移方程了。

//1300:鸡蛋的硬度 
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[110][11];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(f,0,sizeof(f));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                f[i][j]=i;
        for(int j=1;j<=n;j++)
            for(int i=2;i<=m;i++)
                for(int k=1;k<=j;k++)//枚举
                    f[j][i]=min(f[j][i],max(f[k-1][i-1],f[j-k][i])+1);
        /*在1~j层楼间选择第k层扔下鸡蛋,如果破了,说明硬度介于1~k-1之间 ,
        问题变成用i-1个鸡蛋去测k-1层楼的硬度。如果没破则说明硬度介于k~j之间,
        问题变成用i个鸡蛋去测j-k层楼的硬度,题目要求是最坏的情况下,故要取两者最大值 */ 
        printf("%d\n",f[n][m]);
    }
    return 0;
}
1300鸡蛋的硬度代码

猜你喜欢

转载自www.cnblogs.com/wendcn/p/11318223.html