【图论】网络流
网络流问题,包括最大流最小割、费用流
学网络流可以去写著名的网络流24题(搜索引擎随便搜就能有整理和题解),反正我没写完,网络流建模方法非常抽象(?)和有意思。
定义和记法
-
容量网络:有向图,图的边$ (u, v)$ 有非负的权,称容量,图中有一个被称为源的节点和一个被称为汇的节点。
-
实际通过每条边的流量记为$ f(u, v)c(u, v) − f(u, v)$。
-
所有边上的流量集合被称为网络流。
-
在容量网络中,可行流满足:
- 非源汇点,总出量=总入量
-
割:划分成 和 两个点集使得源点在 ,汇点在 。
-
割的容量: 到 所有边的流量之和。求过最大流后的最小割在残余网络中一定出满流,入零流。
最大流/最小割
-
最大流量
-
分为两类,增广路和预流推进
-
增广路即找残差网络上能够从源点到汇点的路,建反图储存每一次增广路最大流,便于反悔
-
最小割的点集找法:跑完最大流在残差网络从源点走残量大于 的边,都是 里的
-
最大流的多解:跑完最大流在残差网络里找正环(原理待补)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36bool vst[N], no[N];
int st[N], top;
bool dfs(int u, int from, bool flag)
{
vst[u] = true;
st[top++] = u;
for (int i = head[u]; ~i; i = edge[i].nxt)
{
int v = edge[i].to;
if (edge[i].cap <= edge[i].flow || v == from)
continue;
if (!vst[v])
{
if (dfs(v, u, edge[i ^ 1].flow < edge[i ^ 1].cap))
return true;
}
else if (!no[v])
return true;
}
if (!flag)
{
while (1)
{
int v = st[--top];
no[v] = true;
if (v == u)
break;
}
}
return false;
}
// 跑完最大流后调用
memset(vis, false, sizeof(vis));
memset(no, false, sizeof(no));
top = 0;
bool flag = dfs(end, end, 0);
Ford-Folkerson
复杂度跟流量有关,一般不用
建图
1 | struct Edge |
暴力dfs求解
1 | bool vst[N]; |
Edmonds-Karp
BFS找增广路,每碰到汇点就增广,复杂度 ,一般不用。
1 | struct Edge |
Dinic
- 每次都走最短的增广路,允许多条增广路一起增广。
- BFS分层,形成层次网络
- 每次只走的路,确保找到最短的增广路,且每条边只走一次,即一个可走弧优化和只走一次的剪枝
- bfs能走的时候,不断dfs增广路
- 最坏复杂度
1 | int dep[N], Q[N]; |
kuangbin的板子:
1 | int Q[N]; |
ISAP
优化Dinic的反复bfs:每次找到的增广路上节点都将层数+1,直到断层或源点层数为n
1 | int Q[N]; |
对偶图
- 平面图中边分开的每个区域设成一个节点,每条边左右的区域连边,左右是同一区域连的就是自环,得到原图的对偶图
- 对偶图上求解最短路=最大流=最小割
技巧
- 技巧1:超级源点和超级汇点的建立
- 技巧2:点有流量限制:拆点成 和 ,入边接in,出边从out接,这两点之间连一条点流量限制的边。
- 技巧3:容量的含义可以想到“限制”有关的题
费用流
最小/大费用最大流:每条路有收费
这里给出最小费用算法,最大费用将费用取相反数,结果再取相反数
SPFA
1 | //建图:Edge多一个cost变量,建图时正边赋cost,反边赋-cost,其他不变 |
最小费用可行流
-
考虑一张网络流图,每条边定义为,代表从 到 的一条有向边,费用为 ,容量为 闭区间,源点 汇点 已知,且保证源点没有入边、汇点没有出边,同时定义常规费用流图的边为
-
现在我们需要求这张图的最小费用可行流(就是满足所有边的流量上下限制,同时费用最小)
-
按照如下方式建立附加边和附加点:
-
建立附加源点 ,和附加汇点
-
对于原图中每一个点(包括源汇) ,令 代表 点的所有入边的流量下界减去出边的流量下界
- 如果 是负数,那么从 连一条边 到
- 如果 是正数,那么从 连一条边 到
-
对于原图中每一条边 ,连边
-
-
连边 (注意这里是原图的源汇点!不是附加的源汇点!!)
-
这样以后,从 到$ TT$ 跑新图的最小费用最大流,再加上原图中每条边的下界流量乘以费用(必须跑的部分),就是最小费用可行流的费用了s