题目链接:BZOJ3876
题目大意
有一个有向无环联通图,每条边有费用,1号点入度为0。每趟可以从1号点开始,可以走到任意一点结束,要求每条边走一遍,可以走多趟,问最小化费用。
分析
上下界费用流,相关知识在上下界网络流。
1. 新建源汇S,T。
2. 对于每条边
ai bi ci
:S向
bi
连边,流量为1,费用为
ci
;
ai
向T连边,流量为1,费用为0;
ai
向
bi
连边,流量为INF,费用为
ci
。
3. 对于每个非1号点,向1号点连边,流量为INF,费用为0。然后跑一遍费用流。
上代码
// 极限时限,大常数反面典型
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 3e2 + 10;
const int M = 2e4 + 10;
const int INF = 0x3f3f3f3f;
int n;
inline int read() {
register char ch = getchar();
register int ans = 0, neg = 1;
for (; !isdigit(ch); ch = getchar())
if (ch == '-') neg = -1;
for (; isdigit(ch); ch = getchar())
ans = ans * 10 + ch - '0';
return ans * neg;
}
int S, T;
int cnt, id[N];
int head[N], len;
struct Lib {
int to, nxt, flow, cost;
inline void add(int a, int b, int c, int d) {
to = b, flow = c, cost = d;
nxt = head[a], head[a] = len++;
}
} lib[M << 1];
inline void makePath(int a, int b, int c, int d) {
lib[len].add(a, b, c, d), lib[len].add(b, a, 0, -d);
}
inline void init() {
n = read(), len = 2;
S = ++cnt, T = ++cnt;
for (int i = 1; i <= n; ++i) id[i] = ++cnt;
for (int i = 1; i <= n; ++i) {
if (i != 1) makePath(id[i], id[1], INF, 0);
for (int j = 1, k = read(); j <= k; ++j) {
int a = read(), b = read();
makePath(S, id[a], 1, b);
makePath(id[i], T, 1, 0);
makePath(id[i], id[a], INF, b);
}
}
}
queue <int> Q;
bool inQ[N];
int dist[N], preV[N], preE[N];
bool SPFA() {
memset(dist, 0x3f, sizeof(dist));
dist[S] = 0, Q.push(S), inQ[S] = true;
while (!Q.empty()) {
int tmp = Q.front();
Q.pop(), inQ[tmp] = false;
for (int p = head[tmp]; p; p = lib[p].nxt) {
int now = lib[p].to, cost = lib[p].cost;
if (lib[p].flow && dist[now] > dist[tmp] + cost) {
dist[now] = dist[tmp] + cost;
preE[now] = p, preV[now] = tmp;
if (!inQ[now]) Q.push(now), inQ[now] = true;
}
}
}
return dist[T] < INF;
}
int MCMF() {
int ans = 0;
while (SPFA()) {
int maxf = INF;
for (int i = T; i != S; i = preV[i])
maxf = min(maxf, lib[preE[i]].flow);
for (int i = T; i != S; i = preV[i])
lib[preE[i]].flow -= maxf, lib[preE[i] ^ 1].flow += maxf;
ans += dist[T] * maxf;
}
return ans;
}
int main() {
init();
printf("%d\n", MCMF());
return 0;
}
以上