HDU 3853 LOOPS:期望dp【网格型】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3853
题意:
有一个n*m的网格。
给出在每个格子时:留在原地、向右走一格,向下走一格的概率。
每走一格会消耗2点体力。
问你从(1,1)到达终点(n,m)消耗体力的期望。
题解:
表示状态:
dp[i][j] = rest steps(剩余路程花费体力的期望)
i,j:现在的位置
找出答案:
ans = dp[0][0]
如何转移:
期望dp的套路:考虑子期望。。。
now: dp[i][j]
能转移到的子期望:dp[i][j](留在原地),dp[i][j+1](向右),dp[i+1][j](向下)
dp[i][j] = dp[i][j]*trans[i][j][0]
+ ( dp[i][j+1]*trans[i][j][1]
+ dp[i+1][j]*trans[i][j][2] + 2 )
移项:
dp[i][j] = ( dp[i][j+1]*trans[i][j][1]
+ dp[i+1][j]*trans[i][j][2] + 2 )
/ (1-trans[i][j][0])
边界条件:
dp[n-1][m-1] = 0
到达终点后不用再耗体力。
注:(1)对于所有越界的概率应看成0。
(2)除法要保证除数不为0。
AC Code:
1 // state expression: 2 // dp[i][j] = rest steps 3 // i,j: present pos 4 // 5 // find the answer: 6 // ans = dp[0][0] 7 // 8 // transferring: 9 // now: dp[i][j] -> dp[i][j], dp[i+1][j], dp[i][j+1] 10 // dp[i][j] = dp[i][j]*trans[i][j][0] 11 // + (dp[i][j+1]*trans[i][j][1] 12 // + dp[i+1][j]*trans[i][j][2] + 2) 13 // dp[i][j] = (dp[i][j+1]*trans[i][j][1] 14 // + dp[i+1][j]*trans[i][j][2] + 2) 15 // / (1-trans[i][j][0]) 16 // 17 // boundary: 18 // dp[n-1][m-1] = 0 19 #include <iostream> 20 #include <stdio.h> 21 #include <string.h> 22 #define MAX_N 1005 23 24 using namespace std; 25 26 int n,m; 27 double dp[MAX_N][MAX_N]; 28 double trans[MAX_N][MAX_N][3]; 29 30 void read() 31 { 32 for(int i=0;i<n;i++) 33 { 34 for(int j=0;j<m;j++) 35 { 36 for(int k=0;k<3;k++) 37 { 38 scanf("%lf",&trans[i][j][k]); 39 } 40 } 41 } 42 } 43 44 void solve() 45 { 46 memset(dp,0,sizeof(dp)); 47 for(int i=n-1;i>=0;i--) 48 { 49 for(int j=m-1;j>=0;j--) 50 { 51 if(i==n-1 && j==m-1) continue; 52 if(trans[i][j][0]==1.0) continue; 53 dp[i][j]=(dp[i][j+1]*trans[i][j][1]+dp[i+1][j]*trans[i][j][2]+2.0)/(1.0-trans[i][j][0]); 54 } 55 } 56 } 57 58 void print() 59 { 60 printf("%.3f\n",dp[0][0]); 61 } 62 63 int main() 64 { 65 while(scanf("%d%d",&n,&m)!=EOF) 66 { 67 read(); 68 solve(); 69 print(); 70 } 71 }