[HDU 3853]LOOPS[概率DP]

[HDU 3853]LOOPS[概率DP]

题目大意

给定一个 \(R * C\) 的网格图,每个格子有三个实数 \(p0,p1,p2\) 分别代表当前格子不跳,向下跳一格和向右跳一格的概率,问从 \((1,1)\)\((R,C)\) 的期望的两倍。

  • 数据范围:\(R, C \leq 1000\)

解题方法

\(f[i][j]\) 表示在第 \((i,j)\) 到达终点的期望,则有转移方程:

\[\begin{align*} &f[i][j] = p[i][j][0]\times f[i][j]+p[i][j][1]\times f[i][j+1] + p[i][j][2]\times f[i + 1][j]+ 2\\ \Rightarrow& f[i][j]=\frac{p[i][j][1]\times f[i][j+1]+p[i][j][2]\times f[i+1][j]+2}{1-p[i][j][0]} \end{align*} \]

从后向前推即可。

  • 注意事项:
    • 多组数据
    • 若某个点 \(p[i][j][0]=1\),则 \(f[i][j]=0\) 需要特判

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;

const int N = 1e3 + 7;
double dp[N][N], p[N][N][3];
int r, c;

int main() {
    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", &p[i][j][0], &p[i][j][1], &p[i][j][2]);
            }
        }
        memset(dp, 0, sizeof dp);
        for(int i = r; i; i--) {
            for(int j = c; j; j--) {
                if(i == r && j == c) continue;
                if(fabs(p[i][j][0] - 1) < 1e-6) continue;
                dp[i][j] = (p[i][j][1] * dp[i][j + 1] + p[i][j][2] * dp[i + 1][j] + 2) / (1 - p[i][j][0]);
            }
        }
        printf("%.3lf\n", dp[1][1]);
    }
    return 0;
}
posted @ 2020-08-21 09:49  iNx  阅读(122)  评论(0编辑  收藏  举报