題目連結: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 }