Description
Solution
先假设没有自环。直接按拓扑序进行DP。
设 表式点 到 的期望代价。
把出边与出点的 两两匹配,形成 个二元组。然后考虑求出匹配方案的最小值 当前二元组的概率。算概率等同于算方案数。Rabbit Number即可。
如果有自环,发现题目要求保存 位小数,可以把当前的 丢进去迭代计算,直到误差很小时停止。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1005;
int n, m, s, t;
struct edge
{
int to, next;
double w;
} e[maxn * 2];
int h[maxn], tot;
bool vis[maxn], to[maxn];
double f[maxn];
int cnt_a, cnt_b, cnt_c, cnt_p, cnt_q, cnt_r;
double a[maxn], b[maxn];
pair<double, int> p[maxn * maxn], q[maxn * maxn], r[maxn * maxn];
int cnt[maxn];
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
inline void add(int u, int v, double w)
{
e[++tot] = (edge) {v, h[u], w};
h[u] = tot;
}
void pre(int u)
{
cnt_a = cnt_b = cnt_c = cnt_p = 0;
for (int i = h[u]; i; i = e[i].next) a[++cnt_a] = e[i].w;
for (int i = h[u], v; v = e[i].to, i; i = e[i].next) if (v != u) b[++cnt_b] = f[v]; else ++cnt_c;
sort(a + 1, a + cnt_a + 1);
sort(b + 1, b + cnt_b + 1);
for (int i = 1; i <= cnt_a; ++i)
for (int j = 1; j <= cnt_b; ++j)
p[++cnt_p] = make_pair(a[i] + b[j], j);
sort(p + 1, p + cnt_p + 1);
}
double calc(double y)
{
int t = 0;
while (t < cnt_b && b[t + 1] < y) ++t;
for (int i = 1; i <= cnt_p; ++i) if (p[i].second > t) p[i].second += cnt_c;
cnt_q = 0;
for (int i = 1; i <= cnt_a; ++i)
for (int j = 1; j <= cnt_c; ++j)
q[++cnt_q] = make_pair(a[i] + y, j + t);
merge(p + 1, p + cnt_p + 1, q + 1, q + cnt_q + 1, r + 1); cnt_r = cnt_p + cnt_q;
for (int i = 1; i <= cnt_p; ++i) if (p[i].second > t) p[i].second -= cnt_c;
for (int i = 1; i <= cnt_a; ++i) cnt[i] = cnt_a - i + 1;
double P = 1, res = 0, lst = 0;
for (int i = 1, x; i <= cnt_r; ++i) {
res += P * (r[i].first - lst); lst = r[i].first;
x = r[i].second;
P = P / cnt[x] * (cnt[x] - 1); --cnt[x];
if (P < 1e-9) break;
}
return res;
}
double dfs(int u)
{
if (vis[u]) return f[u];
vis[u] = 1;
for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
if (v != u) dfs(v), to[u] |= to[v];
if (!to[u]) f[u] = 1e9;
else {
pre(u);
if (!cnt_c) f[u] = calc(0);
else {
double lst = 1e9 + 1; f[u] = 1e9;
while (lst - f[u] > 1e-6) {
lst = f[u];
f[u] = calc(lst);
}
}
}
return f[u];
}
int main()
{
//freopen("shuffle5.in", "r", stdin);
freopen("shuffle.in", "r", stdin);
freopen("shuffle.out", "w", stdout);
n = gi(); m = gi(); s = gi(); t = gi();
double c;
for (int u, v, i = 1; i <= m; ++i) {
u = gi(); v = gi(); scanf("%lf", &c);
add(u, v, c);
}
vis[t] = to[t] = 1;
dfs(s);
if (!to[s]) puts("-1");
else printf("%.6lf", f[s]);
return 0;
}