POJ-3682King Arthur's Birthday Celebration(概率DP)

来源:互联网 发布:2017东南大学软件学院 编辑:程序博客网 时间:2024/04/30 08:44

题意:国王要庆祝他的第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;}


0 0
原创粉丝点击