首先推荐一篇很好的如何概率期望问题的入门文章:点击打开链接
昨天比赛的时候面对这道题的第一想法是依照数学期望的定义来做,即依次求出某个点扔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;
}