题意
这是一道模板题。
n
n
n个点,
m
m
m条边,每条边
e
e
e 有一个流量下界lower(e)和流量上界upper(e),求一种可行方案使得在所有点满足流量平衡条件的前提下,所有边满足流量限制。
思路
取自大佬博客
具体地,如果一个点i在原网络上的附加流中需要满足流入量 > > >流出量(初始流中流入量 < < <流出量, A [ i ] < 0 A[i]<0 A[i]<0),那么我们需要给多的流入量找一个去处,因此我们建一条从 i i i出发流量 = − A [ i ] =-A[i] =−A[i]的边.如果 A [ i ] > 0 A[i]>0 A[i]>0,也就是我们需要让附加流中的流出量 > > >流入量,我们需要让多的流出量有一个来路,因此我们建一条指向 i i i的流量 = A [ i ] =A[i] =A[i]的边.
最后,每条边在可行流中的流量 = = =容量下界 + + +附加流中它的流量(即跑完 d i n i c dinic dinic之后所加反向边的权值).
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int inf = 1 << 29, N = 211, M = 10201;
int n, m, s, t, upper, tot = 1;
int edge[(N + M) * 2], head[N], next[(N + M) * 2], ver[(N + M) * 2], pos[M], dep[N], d[N], lower[M];
std::queue<int> q;
void add(int x, int y, int z) {
ver[++tot] = y;
edge[tot] = z;
next[tot] = head[x];
head[x] = tot;
ver[++tot] = x;
edge[tot] = 0;
next[tot] = head[y];
head[y] = tot;
}
bool bfs() {
memset(dep, 0, sizeof(dep));
while (q.size()) q.pop();
q.push(s);
dep[s] = 1;
while (q.size()) {
int x = q.front();
q.pop();
for (int i = head[x]; i; i = next[i]) {
if (edge[i] && !dep[ver[i]]) {
q.push(ver[i]);
dep[ver[i]] = dep[x] + 1;
if (ver[i] == t) return 1;
}
}
}
return 0;
}
int dinic(int x, int flow) {
if (x == t) return flow;
int rest = flow, k;
for (int i = head[x]; i && rest; i = next[i])
if (edge[i] && dep[ver[i]] == dep[x] + 1) {
k = dinic(ver[i], std::min(rest, edge[i]));
if (!k) dep[ver[i]] = 0;
edge[i] -= k;
edge[i ^ 1] += k;
rest -= k;
}
return flow - rest;
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d %d %d %d", &s, &t, &lower[i], &upper);
d[s] -= lower[i];
d[t] += lower[i];
add(s, t, upper - lower[i]);
pos[i] = tot;
}
s = 0;
t = n + 1;
int all = 0;
for (int i = 1; i <= n; i++) {
if (d[i] > 0) add(s, i, d[i]), all += d[i];
else add(i, t, -d[i]);
}
int flow = 0, maxflow = 0;
while (bfs())
while (flow = dinic(s, inf))
maxflow += flow;
if (all == maxflow) {
printf("YES\n");
for (int i = 1; i <= m; i++)
printf("%d\n", edge[pos[i]] + lower[i]);
} else printf("NO\n");
}