首页 > 代码库 > hdu4405--Aeroplane chess+概率期望dp

hdu4405--Aeroplane chess+概率期望dp

首先推荐一篇很好的如何概率期望问题的入门文章:点击打开链接

昨天比赛的时候面对这道题的第一想法是依照数学期望的定义来做,即依次求出某个点扔i次骰子能到达n点的概率,然后由期望的定义就可以求出答案了。但显然这在程序上是不可能实现的。

今天看了那篇文章后才知道自己的想法是大错特错的;求解这种问题应该采用一种递推的思路,即每次只考虑一次转移后当前状态的期望,然后我们依次考虑每个节点就可以得到一个方程组,然后就只需要求解这个方程组就行了。

当然对于如何求解这个方程组,我们可以采用高斯消元法,当然如果这个方程是递推形式的(如这个题)我们可以直接递推求解就行。

下面就以题目的样例一具体解说一下求解过程

定义Ei表示第i个点到达第n点及其以后点的期望

对于第一个样例n=2

E0=1/6*E1+1/6*E2+1 (加1是因为这是再第一个点扔了一次骰子后的情况,另外E3---E6都是等于E2=0的,所以不写)

E1=1/6*E2+1

然后我们知道E2=0 所以只要先求出E1然后再求出E0就行,即求解过程就是一个倒退的过程。

最后对于这个题目,还定义了一种”飞行线“,对于这个情况,如果某个点直接和其后面的点相连,那么它的期望就等于后面那个点的期望不需要进行状态转移。


代码如下:


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

double f[100010];
int m[100010];

int main()
{
     int n,k;
     while(scanf("%d%d",&n,&k))
     {
             if(n+k==0)
                 break;
             memset(m,-1,sizeof(m));
             for(int i=0;i<k;i++)
             {
                    int x,y;
                    scanf("%d%d",&x,&y);
                    m[x]=y;
             }
             memset(f,0,sizeof(f));
             for(int i=n-1;i>=0;i--)
             {
                    if(m[i]!=-1)
                       f[i]=f[m[i]];
                    else
                    {
                         for(int j=1;j<=6;j++)
                         {
                               if(i+j<=n)
                                  f[i]+=1.0/6*f[i+j];
                         }
                         f[i]+=1.0;
                    }
             }
             printf("%.4lf\n",f[0]);
     }
   return 0;
}


hdu4405--Aeroplane chess+概率期望dp