E - Eggs broken
Time Limit: 5000/2000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
There is a building which is n floors high. Bob has K same eggs now. It is known that, the egg will be broken if Bob throws it from the nth floor. Now Alice is wondering, what's the minimum expected times Bob will throw eggs until he finds the smallest x , if Bob throws an egg from the xth floor the egg will be broken.
The x is distributed in [1,n] uniformly.
As is known to everyone of you, Bob loves Alice very much. Could you tell Bob the answer to help Bob leave a good impression on Alice.
Input
The first line contains two integers n and K , which denote the number of floors and the number of eggs Bob has now.
It is guaranteed that 1≤n≤1000,1≤K≤15
Output
Print the minimum expected times Bob will throw eggs in one line.
The answer should be rounded to 5 digits after the decimal point.
Sample input and output
Sample Input | Sample Output |
---|---|
4 2 | 2.00000 |
题意
有n层楼,k个蛋。已知从n摔下去蛋一定碎,0层摔下去一定不碎。你要找到一个x使蛋在第x层刚好摔碎(x-1不会碎)。然后这个x在[1,n]楼的分布是均匀的。让你求找到x(一定要找到x!)扔蛋次数的期望。
解析
概率dp。记忆化搜索。感觉每次二分地扔是最优解,事实上并不存在扔蛋最优策略,你只能1到n-1都试一下看那一次的期望最小。f(n,k)表示要有k个蛋来确定区间长为n的楼层,扔蛋次数的期望是f(n,k)。顺便说一句,在k相同的情况下,确定长为L的区间扔蛋次数的期望总是一样的,和楼层的高度没关系,仅与区间长度有关。
转移方程是f(n,k)=min(从i层摔碎了+从i层摔没碎)=min( f(i,k-1)*(i/n)+f(n-i,k)*(1-i/n) ) (0<i<n)
写的时候犯了个愚蠢的错误,初始化ans=1……ans是期望不是概率,极大值不能设成1。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int N,K;
double dp[1010][16];
double f(int n,int k)//确定区间长度为N的X,有k个蛋,返回的是扔的次数的期望
{
if(dp[n][k]>0) return dp[n][k];
if(n==1) return 0;
if(k==0) return 0x3f3f3f3f;
double ans=0x3f3f3f3f;
for(int i=1;i<n;i++)//假设这次我从i扔下去
{
double p1=(double)i/n;//有p1的几率会烂
double exception=f(i,k-1)*p1//烂了,然后下楼
+f(n-i,k)*(1-p1);//没烂,上楼
ans=min(ans,exception);
}
//printf("f(%d,%d)=%.5f\n",n,k,ans+1);
return dp[n][k]=ans+1;
}
int main()
{
memset(dp,0,sizeof(dp));
scanf("%d%d",&N,&K);
printf("%.5lf\n",f(N,K));
return 0;
}