bzoj 4349: 最小树形图
最小树形图模板题……
这种\(O(nm)\)的东西真的能考到么……
#include <bits/stdc++.h> #define N 60 #define INF 1000000000 using namespace std; int n, m, nn; double ai[N], an[N], ci[2][N][N], ans; int bc[N]; int ini[N], vis[N], inc[N], inl[N]; int dfn; int dfs(int t) { vis[t] = dfn; if (vis[ini[t]] == vis[t]) return ini[t]; else if (vis[ini[t]]) return 0; else return dfs(ini[t]); } int main() { scanf("%d", &n); for (int i = 0; i <= n; ++ i) for (int j = 0; j <= n; ++ j) ci[0][i][j] = INF; for (int i = 1; i <= n; ++ i) scanf("%lf%d", &ai[i], &bc[i]), an[i] = ai[i], ci[0][0][i] = ai[i]; scanf("%d", &m); for (int i = 1; i <= m; ++ i) { int a, b; double c; scanf("%d%d%lf", &a, &b, &c); if (a != b) ci[0][a][b] = min(ci[0][a][b], c); an[b] = min(an[b], c); } for (int i = 1; i <= n; ++ i) ans += an[i] * (bc[i] - 1); int tmp = 0, wh = 1; nn = n; while (wh) { wh = 0; for (int i = 1; i <= nn; ++ i) { double mn = INF; for (int j = 0; j <= nn; ++ j) if (ci[tmp][j][i] < mn) mn = ci[tmp][j][i], ini[i] = j; } for (int i = 0; i <= nn; ++ i) vis[i] = 0; vis[0] = -1; for (int i = 1; i <= nn; ++ i) if (!vis[i]) { dfn ++; int x = dfs(i); if (x) { int tot = 0; wh = 1; for (int j = 0; j <= nn; ++ j) inc[j] = 0; for (int j = ini[x]; j != x; j = ini[j]) inc[j] = 1; inc[x] = 1; for (int j = 0; j <= nn; ++ j) if (!inc[j]) inl[j] = tot ++; else ans += ci[tmp][ini[j]][j]; for (int j = 0; j <= nn; ++ j) for (int k = 0; k <= nn; ++ k) ci[!tmp][j][k] = INF; for (int j = 0; j <= nn; ++ j) for (int k = 0; k <= nn; ++ k) { if (!inc[j]) { if (!inc[k]) ci[!tmp][inl[j]][inl[k]] = min(ci[!tmp][inl[j]][inl[k]], ci[tmp][j][k]); else ci[!tmp][inl[j]][tot] = min(ci[!tmp][inl[j]][tot], ci[tmp][j][k] - ci[tmp][ini[k]][k]); } else if (!inc[k]) ci[!tmp][tot][inl[k]] = min(ci[!tmp][tot][inl[k]], ci[tmp][j][k]); } nn = tot; break; } } if (!wh) for (int i = 1; i <= nn; ++ i) ans += ci[tmp][ini[i]][i]; else tmp ^= 1; } printf("%.2lf", ans); }