题解:CF1874C Jellyfish and EVA
题目简述
有向无环图,边从小编号指向大编号。从 1 出发要到 n。每步在 u 时,水母选一条出边(最优),明日香随机等概率选一条出边。若两边指向相同顶点,则到达该点;否则留在 u 且这两条边被摧毁。若 \(u \neq n\) 且无出边则失败。求成功最大概率。
n 总和 ≤5000,m 总和 ≤2e5。
模拟赛又输了。。。
分析
假设当前在节点 \(u\),\(v \in son_u\) 最优策略显然是尽可能先去那些更可能到达中点的 \(v\),自然的设计 \(f_u\),表示从 \(u\) 到 \(n\) 的最大成功概率,因为这样在计算 \(f_u\) 的时候已经知道 \(f_v\) 了。
考虑怎么求转移系数,设 \(g_{i,j}\) 表示一个后继儿子个数为 \(i\) 的点,去第 \(j\) 优的儿子的概率,显然可以预处理。
#include<bits/stdc++.h>
#define int long long
#define rep(i, l, r) for(int i = (l); i <= (r); ++ i)
#define per(i, r, l) for(int i = (r); i >= (l); -- i)
#define fi first
#define se second
#define endl '\n'
#define pii pair<int, int>
#define ull unsigned long long
#define pb push_back
using namespace std;
const int N = 5000 + 10;
int d[N];
double f[N], h[N], g[N][N];
vector<int> p[N], son[N];
void Jail() {
int n, m;
cin >> n >> m;
rep(i, 1, m) {
int u, v;
cin >> u >> v;
p[v].pb(u);
son[u].pb(v);
d[u] ++;
}
rep(i, 1, n) {
g[i][1] = 1.0 / i;
rep(j, 2, i) {
g[i][j] = g[i - 2][j - 2] * (j - 2) / i + g[i - 2][j - 1] * (i - j) / i;
}
}
f[n] = 1;
queue<int> q;
rep(i, 1, n) if(d[i] == 0) q.push(i);
while(! q.empty()) {
int u = q.front();
q.pop();
int cnt = 0;
for(auto v : son[u]) {
h[++ cnt] = f[v];
}
sort(h + 1, h + cnt + 1, greater<double>());
rep(i, 1, cnt) {
f[u] += h[i] * g[cnt][i];
}
for(auto t : p[u]) {
d[t] --;
if(d[t] == 0) q.push(t);
}
}
cout << fixed << setprecision(12) << f[1] << '\n';
rep(i, 1, n) {
son[i].clear();
p[i].clear();
f[i] = 0;
d[i] = 0;
}
}
signed main() {
// freopen("drive.in", "r", stdin);
// freopen("drive.out", "w", stdout);
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
ios :: sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T = 1;
cin >> T;
while(T --) Jail();
return 0;
}

浙公网安备 33010602011771号