这种题主要就是推状态转移方程..推公式
解析:
设dp[i][j]表示(i,j)到(R,C)需要消耗的能量[这个定义很重要!]
则:
dp[i][j]=p1[i][j]*dp[i][j]+p2[i][j]*dp[i][j+1]+p3[i][j]*dp[i+1][j]+2;(走一步,额外消耗能量2)
化简得到:
dp[i][j]=p2[i][j]*dp[i][j+1]/(1-p1[i][j])+p3[i][j]*dp[i+1][j]/(1-p1[i][j])+2/(1-p1[i][j]);
注意一种情况就是p1[i][j]==1的情况。(除0错误)
题目只是保证答案小于1000000.但是有的点可能永远都不可能到达的。
所以这样的点出现p1[i][j]是允许的。
否则就会WA了。
转自:http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710606.html
#include<cstdio> #include<cmath> using namespace std; const int MAXN=1010; const double eps=1e-5; double dp[MAXN][MAXN]; double p1[MAXN][MAXN]; double p2[MAXN][MAXN]; double p3[MAXN][MAXN]; int main() { int R,C; while(scanf("%d%d",&R,&C)!=EOF) { for(int i=1;i<=R;i++) for(int j=1;j<=C;j++) scanf("%lf%lf%lf",&p1[i][j],&p2[i][j],&p3[i][j]); dp[R][C]=0;///倒着推! for(int i=R;i>=1;i--) for(int j=C;j>=1;j--) { if(i==R&&j==C)continue; if(fabs(1-p1[i][j])<eps)continue; dp[i][j]=p2[i][j]/(1-p1[i][j])*dp[i][j+1]+p3[i][j]/(1-p1[i][j])*dp[i+1][j]+2/(1-p1[i][j]); } printf("%.3lf\n",dp[1][1]); } return 0; }
自己敲一遍:
#include <cstdio> #include <cmath> using namespace std; const int MAXN = 1005; const double EPS = 1e-5; double dp[MAXN][MAXN],p1[MAXN][MAXN],p2[MAXN][MAXN],p3[MAXN][MAXN]; /** dp[i][j] 表示从(i,j)到(R,C)耗费的能量 状态转移: dp[i][j] = (p2[i][j]*dp[i+1][j] + p3[i][j]*dp[i][j+1] + 2) / (1 - p1[i][j]); 注意避免除0错误 **/ int main() { int R,C; while(scanf("%d%d",&R,&C)==2) { for(int i=1;i<=R;i++) for(int j=1;j<=C;j++) scanf("%lf%lf%lf",p1[i]+j,p2[i]+j,p3[i]+j); dp[R][C] = 0;///由于没有越界的操作,也不涉及"坑"的值,也就不需要memset了,只要初始化终点即可 for(int i=R;i>0;i--) for(int j=C;j>0;j--) { if(i==R && j==C) continue; if(fabs(1 - p1[i][j])<EPS) continue;///为什么这里不赋值? ///如果到达这里的概率是p,那么从这里到终点的能量应该是INF,那么总的期望..? ///显然也是INF.也就是说只要有可能走不出,那么期望就是走不出. ///从AC的情况反推数据,应该是,有p1==1的点,但是左和上数据[保证]不会走到这一点 ///所以这一点的值是无所谓的,只要在计算它自己的时候避免一下除零错误,跳过就行了 ///好吧,其实题目说<1000000,意思不只是限制在int内,还表明了没有INF的情况... dp[i][j] = (p2[i][j]*dp[i][j+1] + p3[i][j]*dp[i+1][j] + 2) / (1 - p1[i][j]); } printf("%.3lf\n",dp[1][1]); } }