CF605E Intergalaxy Trips
正着来不好,考虑反着来。设 \(f_{i}\) 为第 \(i\) 个点开始走到第 \(n\) 个点的期望步数。
考虑什么情况会最优,显然是能到的点的期望都比它大,并且j不能只有自环,于是乎有方程。
\[f_i=\sum_j {f(j)\over 1-\prod (1-e[j][k])}\cdot e[i][j]\prod_{k,f_k < f_j}(1-e_{i,k})
\]
dp顺序很难确定,我们用类似 dijkstra 的方法即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e3 + 5;
const double inf = 1e-9;
double e[N][N], f[N], pr[N];
int vis[N];
inline int read() {
register int s = 0; register char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) s = (s << 1) + (s << 3) + (ch & 15), ch = getchar();
return s;
}
int n;
int main() {
n = read();
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
e[i][j] = 1.0 * read() / 100.0;
memset(vis, 0, sizeof vis);
for (int i = 0; i < n; ++i) f[i] = 1, pr[i] = 1 - e[i][n]; f[n] = 0; vis[n] = 1;
for (int T = 1; T <= n; ++T) {
int j = 1;
for (int i = 2; i <= n; ++i)
if (f[j] / (1.0 - pr[j]) > f[i] / (1.0 - pr[i]) && !vis[i]) j = i;
if (j == 1) break; vis[j] = 1;
for (int i = 1; i <= n; ++i)
f[i] += f[j] / (1.0 - pr[j]) * e[i][j] * pr[i], pr[i] *= (1.0 - e[i][j]);
} printf("%.10lf", f[1] / (1.0 - pr[1]));
return 0;
}