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;
}
posted @ 2021-09-10 21:31  Smallbasic  阅读(38)  评论(0)    收藏  举报