[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;
}