上下界网络流
1. 上下界无源汇可行流
首先为了规避两个限制难以处理,先预先给每条边钦定等同于下界 \(l\) 的流量。
然后需要调整一些边使得流量平衡。显然可以给每条边 \([0, r-l]\) 的额外流量,这时候没有下界影响了,可以直接当做出入度平衡问题,套路地采用 \(S\) 连向入度过大点,出度过大点连向 \(T\),最大流解决。其中 \(S, T\) 是 新建的 超级源汇。
// Super Source / Terminal
int S, T;
const int inf = 0x3f3f3f3f;
namespace Flow {
int cur[maxn], hd[maxn], tot, d[maxn];
struct Edg {
int y, z, nxt;
} e[maxm];
void init() {
memset(hd, 0, sizeof(hd)), tot = 1;
}
void add(int x, int y, int z) {
e[++tot] = {y, z, hd[x]}, hd[x] = tot;
e[++tot] = {x, 0, hd[y]}, hd[y] = tot;
}
bool bfs() {
memcpy(cur, hd, sizeof(hd));
memset(d, 0, sizeof(d));
queue<int> q;
q.push(S), d[S] = 1;
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = hd[x]; i; i = e[i].nxt) {
int y = e[i].y;
if (e[i].z <= 0 || d[y]) continue;
d[y] = d[x] + 1, q.push(y);
if (y == T) return 1;
}
}
return 0;
}
int dinic(int x, int fl) {
if (x == T) return fl;
int res = fl;
for (int i = cur[x]; i && res; i = e[i].nxt) {
cur[x] = i;
int y = e[i].y;
if (e[i].z <= 0 || d[y] != d[x] + 1) continue;
int tp = dinic(y, min(res, e[i].z));
if (!tp) d[y] = -1;
else e[i].z -= tp, e[i ^ 1].z += tp, res -= tp;
}
return fl - res;
}
int solve() {
int ans = 0, tmp;
while (bfs())
while (tmp = dinic(S, inf)) ans += tmp;
return ans;
}
}
// Original Source / Terminal
int s, t, w[maxn];
void add(int x, int y, int l, int r) {
w[x] -= l, w[y] += l, Flow::add(x, y, r - l);
}
void proc(int i) {
if (w[i] > 0) Flow::add(S, i, w[i]);
else if (w[i] < 0) Flow::add(i, T, -w[i]);
}
// Add All Edges, Proc All Nodes (Include s, t)
2. 上下界有源汇可行流
在 原本 包含源点 \(s\)、汇点 \(t\) 的流图基础上,连接范围为 \([0,\infty]\) 的边 \((s,t)\),然后仍然跑 1 中算法。注意不要和 \(S,T\) 弄混。
3. 上下界有源汇最大流
直接在 2 中可行流对应的 残量网络 上,再从 \(s\) 出发到 \(t\) 跑最大流。
理解:首先由于 \(S, T\) 的边都满流,不在残量网络中。所以这时候 \(S, T\) 是不影响的;而且它们相关的边显然不会在 \(s, t\) 间的增广路上,因此我们始终在保证这些边满流的基础上调整其它边,也就始终保证了流量平衡。
4. 上下界有源汇最小费用可行流
直接把 3 中,跑的出入度平衡的最大流改为费用流,给那些范围为 \([0, r - l]\) 的边额外附上费用。
5. 上下界有源汇最小费用最大流
结合 3, 4,全部改为费用流即可。

浙公网安备 33010602011771号