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