您的位置:首页 > 其它

ACM--楼层扔鸡蛋问题

2012-05-10 22:28 176 查看
鸡蛋

TimeLimit:1000MSMemoryLimit:65536K

Description

Gardon有一些鸡蛋,他现在想知道这些鸡蛋的硬度。Gardon的家住在一座很高很高的大楼里,他现在要在这座大楼上测试鸡蛋的硬度。每个鸡蛋的硬度相同,鸡蛋的硬度定义为:如果鸡蛋从第m层上掉下来没有破裂,而从第m+1层上掉下来就破裂了,那么这个鸡蛋的硬度就是m。某个鸡蛋如果在实验中破裂了就永远的损失了。那么在最坏情况下他最少需要做多少次实验呢?他的鸡蛋数量是有限的。

Input

输入包括多组数据,每组数据的第一个数是一个整数N,表示Gardon的鸡蛋数量,第二个数是大楼的高度H,如果鸡蛋的硬度超过H,也按照H计算。

Output

对每组输入数据,输出Gardon在最坏的情况下最少的试验次数,当然必须保证鸡蛋的硬度能够被正确测量出来。

SampleInput

2100110


SampleOutput

1410


类型:动态规划

有关问题的分析,在网上看到一篇写的很好的文章

/*以下为转载内容*/

/*来自http://49px.com/wiki/%E6%A5%BC%E5%B1%82%E6%89%94%E9%B8%A1%E8%9B%8B%E9%97%AE%E9%A2%98*/

楼层扔鸡蛋问题
出自Smilingpoplar

有限层数和蛋数,求即使最坏情况下需要的最少判断次数

两个软硬程度一样但未知的鸡蛋,它们有可能都在一楼就摔碎,也可能从一百层楼摔下来没事。有座100层的建筑,要你用这两个鸡蛋确定哪一层是鸡蛋可以安全落下的最高位置。可以摔碎两个鸡蛋。(参见两个鸡蛋--一道Google面试题)

这是典型的动态规划问题。假设f
表示从n层楼找到摔鸡蛋不碎安全位置的最少判断次数。假设第一个鸡蛋第一次从第i层扔下,如果碎了,就剩一个鸡蛋,为确定下面楼层中的安全位置,必须从第一层挨着试,还需要i-1次;如果不碎的话,上面还有n-i层,剩下两个鸡蛋,还需要f[n-i]次(子问题,实体n层楼的上n-i层需要的最少判断次数和实体n-i层楼需要的最少判断次数其实是一样的)。因此,最坏情况下还需要判断max(i-1,f[n-i])次。


状态转移方程:f
=min{1+max(i-1,f[n-i])|i=1..n}初始条件:f[0]=0(或f[1]=1)


实际上,两个鸡蛋的情况用数学方程就可以解决,前提是你知道该怎么扔:

一种想法是第一个鸡蛋折半搜索,如100层的楼,先从50层扔下去,如果碎了则第二个鸡蛋在1~49层楼中自底向上线性搜索;如果没碎则第一个鸡蛋再从75层扔。如果这次碎了则第二个鸡蛋在51~74层楼中自底向上线性搜索;如果还没碎则第一个鸡蛋再从88层扔,依此类推。这种方法不是最优,因为最坏情况下安全位置恰好是49层,需要尝试50次。

正确的方法是先假设最少判断次数为x,则第一个鸡蛋第一次从第x层扔(不管碎没碎,还有x-1次尝试机会)。如果碎了,则第二个鸡蛋在1~x-1层中线性搜索,最多x-1次;如果没碎,则第一个鸡蛋第二次从x+(x-1)层扔(现在还剩x-2次尝试机会)。如果这次碎了,则第二个鸡蛋在x+1~x+(x-1)-1层中线性搜索,最多x-2次;如果还没碎第一个鸡蛋再从x+(x-1)+(x-2)层扔,依此类推。x次尝试所能确定的最高楼层数为x+(x-1)+(x-2)+...+1=x(x+1)/2。

比如100层的楼,只要让x(x+1)/2>=100,得x>=14,最少判断14次。具体地说,100层的楼,第一次从14层开始扔。碎了好说,从第1层开始试。不碎的话还有13次机会,再从14+13=27层开始扔。依此类推,各次尝试的楼层依次为


1427=14+1339=27+12...99=95+4100


现在推广成n层楼,m个鸡蛋:

还是动态规划。假设f[n,m]表示n层楼、m个鸡蛋时找到摔鸡蛋不碎的最少判断次数。则一个鸡蛋从第i层扔下,如果碎了,还剩m-1个鸡蛋,为确定下面楼层中的安全位置,还需要f[i-1,m-1]次(子问题);不碎的话,上面还有n-i层,还需要f[n-i,m]次(子问题,实体n层楼的上n-i层需要的最少判断次数和实体n-i层楼需要的最少判断次数其实是一样的)。


状态转移方程:f[n,m]=min{1+max(f[i-1,m-1],f[n-i,m])|i=1..n}初始条件:f[i,0]=0(或f[i,1]=i),对所有i


/*以上内容转自http://49px.com/wiki/%E6%A5%BC%E5%B1%82%E6%89%94%E9%B8%A1%E8%9B%8B%E9%97%AE%E9%A2%98*/


下面是我写的一个程序

SourceCode

#include<iostream>#include<cstdio>usingnamespacestd;#defineM100#defineN100intdp[101][101];intmain(){inti,j,k,m,n;memset(dp,0,sizeof(dp));for(i=1;i<=N;i++)dp[1][i]=i;for(j=2;j<=M;j++)for(k=1;k<=N;k++){dp[j][k]=1+max(dp[j-1][0],dp[j][k-1]);for(i=2;i<=k;i++)dp[j][k]=min(dp[j][k],1+max(dp[j-1][i-1],dp[j][k-i]));}while(scanf("%d%d",&m,&n)!=EOF)printf("%d\n",dp[m]
);return0;}

[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: