标签:
题意:玩飞行棋,棋盘有0~n共n+1,每次抛一个6面的骰子,若得到x(1<=x<=6)点,则从i走到i+x格。其中,有些格子是飞机场,只要站在第A格上,就会从第A格直接飞到第B格。当你站在第k格且k >= n时,游戏结束。求抛骰子次数的期望。
解释概率dp加上一个限制条件,说下为什么当有飞机的时候前面的等于后面的,因为dp代表的是当前位置到n的期望, 所以前面的概率等于飞机到达的
转载:
又一道期望DP,其实这题与hdu4576那道概率DP很像(这道我也写了题解)。那么这两道一道求概率,一道求期望,又能放在一起对比一下了,期望和概率的求法的不同。
先总结一句话:一般求概率DP或者是递推的问题,都是正着推,从初始状态往结束状态(结束状态一般是此类题要求的状态)推,所以先得到(或者说先已知)的是靠近初始状态的状态,所以想要求的当前状态是由可转移到此状态的前N可能个状态推过来的;而一般求期望DP,都是逆着推,从结束状态往初始状态(初始状态往往是此类题要求的状态)推,所以先得到(或者说先已知)的是靠近结束状态的状态,所以想要求的当前状态是由此状态对应接下来的N可能个状态推过来的。
本题题意:数轴上有N+1个点(编号0~N),一个人玩游戏,从0出发,当到达N或大于N的点则游戏结束。每次行动掷骰子一次,骰子编号1-6,掷到多少就向前走几步,这个数轴上还有些特殊点,这些点类似飞行棋中的飞行点,只要到达这些点就可以直接飞到给定点。求总共投掷骰子次数的期望。
例如本题,倒着过来分析。用dp[i]表示在i位置时,距离游戏结束还要投掷次数的期望。显然dp[n]为0,需要求的是dp[0]。对于直接飞过去的点。例如用数组vis[]来表示,vis[a]=b,表示当到达a点时可以直接飞到b点,那么显然dp[vis[a]]=dp[a]。倒着推,dp[i](假设该点不属于可飞行的点)的下面一个状态有6种可能(即对应6种可能的骰子数),每种都是1/6的概率。所以for(int x=1;x<=6;x++)dp[i]+=dp[i+x]/6.0;dp[i]+=1;注意最后加玩每种可能性的期望后要+1,因为这6种可能性加起来只是下一个状态的期望,当前状态是他们的前一个状态,所以期望(直接理解为投掷骰子的次数)要+1
#include<stdio.h> #include<iostream> #include<algorithm> #include<math.h> #include<cstring> using namespace std; int f[100005]; double dp[100005]; int main() { int n,m; while(~scanf("%d %d",&n,&m)) { if(n==0&&m==0) break; memset(f,0,sizeof(f)); for(int i=0; i<m; i++) { int a,b; scanf("%d %d",&a,&b); f[a]=b; } memset(dp,0,sizeof(dp)); for(int i=n-1; i>=0; i--) { if(f[i]) { dp[i]=dp[f[i]]; } else { for(int j=i+1; j<=i+6; j++) dp[i]+=dp[j]; dp[i]=dp[i]/6+1; } } printf("%.4f\n",dp[0]); } return 0; }
标签:
原文地址:http://blog.csdn.net/wweiainn/article/details/43962201