问题大意:给你 n 个鸡蛋,问你在 m 层中,进行多少次投鹰蛋能确定,鹰蛋最高在哪层能不碎( 即最坏情况需要多少次 ),
如果第m层也不碎答案为m。
这个问题好像有个大牛写过一篇论文。我只学了其中的两个方法。
第一种方法是 log( n )*n^2,我们将状态设成 dp[ i ][ j ] 表示成有 i 个鸡蛋,层数为 j 时最少需要的实验次数。
那么我们考虑在第一次在 k 层投鹰蛋,有两种情况,一种是鹰蛋碎了 这种状况对应的子问题为dp[ i -1 ][ k-1 ](k层下面的部分),
另一种子问题是鹰蛋没碎为 dp[ i ][ m-k ](k层上面的部分),因为考虑最坏的情况,所以取两者的最大值赋给dp[ i ][ j ],并加上
第一次在k层投的一次。 对于k是哪个,只需要枚举 k 就可以了。考虑鸡蛋充足的情况,那么就是二分的方法,这样对于
i > log(j) 的状态直接赋值。
#include<bits/stdc++.h> using namespace std; const int inf=0x3f3f3f3f; int dp[12][1005],n,m; int main() { //freopen("text2","w",stdout); memset(dp,inf,sizeof(dp)); for(int i=1;i<=1000;i++) dp[1][i]=i; for(int i=1;i<=10;i++) dp[i][1]=1; for(int i=2;i<=10;i++) { for(int j=1;j<=1000;j++) { int res; dp[i][j]=dp[i-1][j];//这里特别注意,wa地生活不能自理。 for(int k=1;k<=j;k++) { dp[i][j]=min(dp[i][j],max(dp[i-1][k-1]+1,dp[i][j-k]+1)); } } } while(scanf("%d%d",&n,&m)!=EOF && n && m) { if(m==0) { puts("0"); continue; } if(n>10) n=10; printf("%d\n",dp[n][m]); } return 0; }
第二种方法是,我们考虑dp[ i ][ j ]为有 j 个鸡蛋进行 i 次能确定的最高楼层。假设在某一层楼扔下一只蛋,且碎了,
则在下面的( j - 1)次里,我们要用(i-1)个蛋在下面的层中确定 E为了使 dp(i,j)达到最大,我们当然希望下面的楼层数达到最多,
这便是一个子问题,答案为 dp[ i - 1 , j - 1 ];假设蛋没碎,则在后面( j - 1)次里,我们要用 i 个蛋在上面的楼层中确定 E,
这同样需要楼层数达到最多,便为 dp[ i - 1 , j ],然后不管怎样,我们都用了一次。即dp[ i , j ]=dp[ i - 1 , j - 1 ] + dp[ i , j - 1 ] + 1。
#include<bits/stdc++.h> using namespace std; LL dp[1010][1010]; int main() { for(int i=1;i<=1000;i++) { dp[1][i]=i; dp[i][1]=1; } for(int i=2;i<=1000;i++) { for(int j=2;j<=1000; j++) { dp[i][j]=dp[i][j-1]+dp[i-1][j-1]+1; } } int n,m; while(cin>>m>>n, n && m) { LL ans=-1; for(int i=1;i<=1000;i++) { if(dp[m][i]>=n) { ans=i; break; } } cout << ans << endl; } return 0; }