【笔记】网络流
感觉会分成好多篇,所以这篇的标题可能不叫网络流(
挖坑
基本模型,有向图,源点 S 汇点 T ,满足每条边的容量限制、除源汇点外的点入流等于出流
最大流
dinic 算法,算法原理什么的先放着(虽然也有用这个出题的),很多时候跑的很快,理论复杂度上界 \(O(n^2m)\) ,二分图上是 \(O(n\sqrt{m})\)
只是...你别把网络流的图潜意识里只想成二分图了...
部分想法,流就是方案的组合,流量限制可以刻画方案间的冲突关系和选择限制
最大流就是最小割,最大流跑完的残量网络是不连通的
有向图最小路径覆盖,二分图跑最大流(最大匹配)
删点令源汇点不连通,将每个点 u 拆成 ...-> u->u' ->... ,容量 1 ,跑最大流,暂时不知道也没去想为什么对了,反正这么做就过了(
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 505;
const int MAXE = 10005;
const int INF = 1e9;
int T, N, E, tote, fst[MAXN], cur[MAXN], dep[MAXN];
struct edge {
int v, w, pre;
} e[MAXE];
void adde(int a, int b, int c, int k)
{
e[k].v = b, e[k].w = c, e[k].pre = fst[a], fst[a] = k;
}
int bfs(int s, int t)
{
memset(dep, 0, sizeof(dep));
queue<int> q;
q.push(s), dep[s] = 1, cur[s] = fst[s];
while (!q.empty()) {
int x = q.front(); q.pop();
for (int o=fst[x]; o!=-1; o=e[o].pre) {
if (e[o].w && dep[e[o].v]==0) {
dep[e[o].v] = dep[x] + 1, cur[e[o].v] = fst[e[o].v];
q.push(e[o].v);
}
}
}
return dep[t];
}
int dfs(int x, int t, int want)
{
if (x==t || !want) return want;
int flow = 0;
for (int o=cur[x]; o!=-1; o=e[o].pre, cur[x]=o) {
if (e[o].w> 0 && dep[e[o].v]==dep[x]+1) {
int f = dfs(e[o].v, t, min(e[o].w, want));
if (!f) continue;
e[o].w -= f, e[o^1].w += f;
want -= f, flow += f;
if (!want) return flow;
}
}
return flow;
}
int dinic(int s, int t)
{
int ans = 0;
while (bfs(s, t)) ans += dfs(s, t, INF);
return ans;
}
int main()
{
for (scanf("%d", &T); T; T--) {
memset(fst, -1, sizeof(fst));
scanf("%d%d", &N, &E); tote = 0;
for (int i=0; i< E; i++) {
int a, b, c; scanf("%d%d%d", &a, &b, &c);
adde(a, b, c, tote++), adde(b, a, 0, tote++);
}
printf("%d\n", dinic(1, N));
}
}
费用流(最小费用最大流)
zkw 算法,算法原理什么的不知道(,反正跑的挺快(
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 5005;
const int MAXE = 100005;
const int inf = 1000000000;
int T, N, E, tote, fst[MAXN], dep[MAXN], vis[MAXN], cost;
struct edge {
int v, c, w, pre;
} e[MAXE];
void adde(int a, int b, int flow, int w, int k)
{
e[k].v = b, e[k].c = flow, e[k].w = w, e[k].pre = fst[a], fst[a] = k;
}
int bfs(int s, int t)
{
memset(dep, 0x3f, sizeof(dep)); int infdep = dep[s];
// be careful if dep could exceed 0x3f
memset(vis, 0, sizeof(vis));
deque<int> q;
q.push_back(t), vis[t] = 1, dep[t] = 0;
while (!q.empty()) {
int x = q.front(); q.pop_front();
for (int o=fst[x]; o!=-1; o=e[o].pre) {
if (e[o^1].c && dep[e[o].v]> dep[x]-e[o].w) {
dep[e[o].v] = dep[x] - e[o].w;
if (!vis[e[o].v]) {
vis[e[o].v] = 1;
if (!q.empty() && dep[e[o].v]< dep[q.front()]) {
q.push_front(e[o].v);
} else q.push_back(e[o].v);
}
}
}
vis[x] = 0;
}
return dep[s]< infdep;
}
int dfs(int x, int t, int want)
{
if (x==t) return want;
int flow = 0;
vis[x] = 1;
for (int o=fst[x]; o!=-1; o=e[o].pre) {
int v = e[o].v;
if (!vis[v] && e[o].c && dep[x]-e[o].w==dep[v]) {
int f = dfs(v, t, min(want, e[o].c));
if (!f) continue;
e[o].c -= f, e[o^1].c += f;
flow += f, want -= f;
cost += f * e[o].w;
if (!want) break;
}
}
return flow;
}
int zkw(int s, int t)
{
int flow = 0;
while (bfs(s, t)) {
vis[t] = 1;
while (vis[t]) {
memset(vis, 0, sizeof(vis));
flow += dfs(s, t, inf);
}
}
return flow;
}
int main()
{
for (scanf("%d", &T); T; T--) {
memset(fst, -1, sizeof(fst));
tote = 0, cost = 0;
scanf("%d%d", &N, &E);
int s, t; s = 1, t = N;
for (int i=1; i<=E; i++) {
int a, b, c, w; scanf("%d%d%d%d", &a, &b, &c, &w);
adde(a, b, c, w, tote++);
adde(b, a, 0, -w, tote++);
}
int flow = zkw(s, t);
printf("%d %d\n", flow, cost);
}
}
[TJOI2010]打扫房间
闭合回路——度为 2 ——黑白染色,源点 -[2]-> 黑点 -[1]-> 白点 -[2]-> 汇点,判断跑满最大流

浙公网安备 33010602011771号