题意:国王要庆祝他的第k个生日,庆祝的时长如下:每天抛一枚硬币,正面朝上的概率为p,当第k次出现正面后,不再庆祝(最后一次出现正面当天还是要庆祝的)。第i天的费用为2*i+1,求时间的期望和费用的期望。
一种解法:
用逆推的方法来求期望。设E[i]为已经出现了i次正面后到庆典结束的时间期望,F[I]为出现i次正面后到庆典结束所需费用的期望。
则有:
E[i]=p(E[i+1]+1)+(1-p)(E[i]+1)
上式可以这么理解:
E[i]状态可以由两种状态转换而来,第一种是抛出了一个正面,概率为p,它的前一个状态是E[i+1],因为又抛了一次,所以要+1.
另外一种状态是抛出了一个反面,概率是1-p,正面的个数并没有变化,所以它的前一个状态还是E[i],同理也要+1
然后可以推出下面的式子:
F[i]=p(F[i+1]+(E[i+1]+1)*2-1)+(1-p)(F[i]+(E[i]+1)*2+1)
在F[i]时,如果抛出了一个正面,概率为p,则期望花费为p*(上一个状态F[i+1]的期望花费+抛的这天的期望花费)
抛的这天为第E[i+1]+1天,所以花费为2*(E[i+1]+1)-1。
同理,如果抛出了一个反面,仍状态i转移而来。
一开始的疑问:i最后一次不是必须为正面吗?由于是逆推,每次枚举的是前一次抛的状态而不是后一次抛的状态。
将上面的式子整理一下,E[i]和F[i]移到一边,就可以得到递推式子了。
最近POJ这道题貌似有点问题:各种曾经AC的代码交上去都是WA......
如果我的方法有误,欢迎指出!
另外一种解法:
http://blog.csdn.net/huyuncong/article/details/7709889
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int N=1000;
double E[N+5],F[N+5];
int main()
{
int i,n;
double p;
while(scanf("%d",&n),n)
{
memset(E,0,sizeof(E));
memset(F,0,sizeof(F));
scanf("%lf",&p);
for(i=n-1; i>=0; i--)
{
E[i]=E[i+1]+1.0/p;
F[i]=F[i+1]+(2*E[i+1]+1)+(1-p)*(2*E[i]+1)/p;
}
printf("%0.3lf %0.3lf\n",E[0],F[0]);
}
return 0;
}