wolf5x
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 402 Accepted Submission(s): 248
Special Judge
这是一维的,一个人在0号格子,如今1~n号格子排成一排,上面有各种限制,一个人想从 0号格子走出n号格子。也就是走到 >n 处。
每一个格子是4种状态的当中一种,而且没告诉你是哪种状态,仅仅是告诉你概率,第i号格子4种状态的当中一种的概率记为p[i][0],p[i][1]。p[i][2],p[i][3]。
0 表示这个格子既不能左腿也不能右腿踏进去。
1 表示这个格子能够左腿踏进去。
2 表示这个格子能够右腿踏进去。
3 表示这个格子既能够左腿也能够右腿踏进去。
这个人刚開始能够选择迈出左腿也能够迈出右腿,可是下次必须迈出不同的腿,除非你走在3这个状态下。下次又能够左右腿选一个,就和走路一样。
这个人一次迈出的步子的范围是[A,B],还有就是假设他迈出的步子能够是A+1或者A+2或者别的。他会选择最少的步数也就是 A+1
问你,这个人走的步数的数学期望,这个人走到 >n 处停止或者不能再走了也停止。
解题思路:
看到了数学期望,我就想到了概率DP。而这题的解法也就是概率DP,这个赛区已经看到了三道DP题目了。
(1)首先。用DP(pos,state) 记录这个状态下你还须要走的步数的数学期望
当中 。pos记录你当前所在的格子,state记录你能够迈出的步子
0 表示你下一步不能走了,也就须要走的步数的数学期望0,是所以不会有这个状态,直接被剪纸剪掉了。
1 表示下一步要用左腿踏进去
2 表示下一步要用右腿踏进去
3 表示下一步既左腿也能够右腿踏进去
那么我么要求的就是DP(0,3)表示在0号格子,下一步既左腿也能够右腿踏进去,这个状态下你还须要走的步数的数学期望
(2)关于递推方程怎么求
DP(pos。state) =sum { p * ( DP(newpos,newstate) + 1 ) }
解释下我写的状态转移方程:
比方说,你当前在s位置,那么就枚举下一步走的位置 i, i>=s+A 且 i<=s+B
你走这个位置的概率,就是前面都不能走。也就是 s~i-1都同一时候为0状态,由于假设不是0状态你就得走,题目交代他会选择最少的步数。
所以得维护 s~i-1都同一时候为0状态的概率,也就是前缀相乘。
那么,如今讨论假设走了第 i 号位置
假设你的这一步要用右腿踏进去。下一步就得用左腿,假设这个位置的状态是3,你下个位置任意。
左腿同理。
解题代码:
#include#include #include using namespace std;const int maxn=2100;double p[maxn][5],dp[maxn][5];int a,b,n,vis[maxn][5],marked;void input(){ scanf("%d%d%d",&n,&a,&b); for(int i=1;i<=n;i++){ for(int j=0;j<4;j++){ scanf("%lf",&p[i][j]); } }}double DP(int k,int state){ if(k>n) return 0; if(k==n) return 1; if(vis[k][state]==marked) return dp[k][state]; double ans=0; if(state==3){ double p0=1.0; for(int i=k+a;i<=k+b;i++){ if(i>n){ ans+=p0*1.0; break; } ans+=p0*p[i][3]*(DP(i,3)+1); ans+=p0*p[i][2]*(DP(i,1)+1); ans+=p0*p[i][1]*(DP(i,2)+1); p0*=p[i][0]; } }else if(state==2){ double p0=1.0; for(int i=k+a;i<=k+b;i++){ if(i>n){ ans+=p0*1.0; break; } ans+=p0*p[i][3]*(DP(i,3)+1); ans+=p0*p[i][2]*(DP(i,1)+1); p0*=(p[i][0]+p[i][1]); } }else{ double p0=1.0; for(int i=k+a;i<=k+b;i++){ if(i>n){ ans+=p0*1.0; break; } ans+=p0*p[i][3]*(DP(i,3)+1); ans+=p0*p[i][1]*(DP(i,2)+1); p0*=(p[i][0]+p[i][2]); } } vis[k][state]=marked; return dp[k][state]=ans;}void solve(){ marked++; printf("%.8lf\n",DP(0,3));}int main(){ int T; scanf("%d",&T); while(T-- >0){ input(); solve(); } return 0;}