网络流小记
I.基本定义:
-
网络:一张有向图。
-
流量:经过一条边的流的大小,一条边
的流量记为 , 一个网络的流量定义为 。 -
容量:一条边的流量上限,一条边
的容量记为 。 -
费用:经过一条边单位流量的所需费用,一条边
的费用记为 。 -
源点:所有流的起始点, 记为
。 -
汇点:所有流的终止点,记为
。 -
割:是网络的一个划分, 一个割 {
} 的容量定义为 。 -
残量网络:每条边剩余可走的流量组成的网络。
网络流的性质:
-
斜对称性:
-
流量守恒:
-
容量限制:
II.一些定理:
增广路定理:
- 增广路:在残量网络中的一条
到 的路径,满足路径上的残量均大于 。
一个流为最大流当且仅当网络中没有增广路,证明显然。
最大流最小割定理:
对于任意网络,最大流
- 证明:首先显然有
,因为根据割的定义 互不相交, 的流量一定大于等于 ,考虑如何构造取到等号。
III.最大流:
EK 算法:
对于求一张图的最大流,我们考虑引入反向边的概念。
- 反向边:一条边的反向边定义为一条流向与原边相反,容量为
,流量与原边相反的边。
经过反向边相当于做退流操作,类似于反悔,这也是 EK 算法的关键之处。具体的,我们将反向边一并加入到残量网络中,并与原边一起考虑。
由上面的定理,我们可以得到以下算法:
-
在残量网络上找一条增广路,将这条路径上的流大小记为
。 -
将路径上的所有边加上
,反向边减掉 。
我们暴力的使用
Dinic 算法:
考虑优化上面的算法,
我们考虑对残量网络进行分层,这样我们可以一次找到多条长度相同的增广路并进行增广。分层容易用
接着我们考虑进行多路增广,这个使用
qwq
一些例题:
(有待修缮)
IV.费用流:
在费用流问题中,每条边多了一个元素称作费用,一个流的费用等于该流经过的边的费用和乘上流的大小。费用流问题中最经典的是最小费用最大流问题,即在最大化流大小的情况下最小化费用和。
其实这个问题非常简单,我们每次选择流最大的增广路中最小费用的进行增广即可。
qwq
namespace Dinic{ struct edge{ int v, flow, cap, cost, next; }edges[M << 1]; int head[N], idx = 1; int cur[N], dis[N], s, t, siz, maxflow, mincost; bool vis[N]; void add_edge(int u, int v, int cap, int cost){ edges[++idx] = {v, 0, cap, cost, head[u]}; head[u] = idx; } void addline(int u, int v, int cap, int cost){add_edge(u, v, cap, cost); add_edge(v, u, 0, -cost);} bool SPFA(){ for(int i = 1; i <= siz; i++) dis[i] = INF, cur[i] = head[i], vis[i] = false; dis[s] = 0; queue<int> Q; Q.push(s); while(!Q.empty()){ int u = Q.front(); Q.pop(); vis[u] = false; for(int i = head[u]; i; i = edges[i].next){ int v = edges[i].v; if(dis[v] > dis[u] + edges[i].cost && edges[i].cap > edges[i].flow){ dis[v] = dis[u] + edges[i].cost; if(!vis[v]) Q.push(v), vis[v] = true; } } } for(int i = 1; i <= siz; i++) vis[i] = false; return (dis[t] != INF); } int dfs(int u, int flow, int &cost){ if((!flow) || u == t) return flow; int ret = 0; vis[u] = true; for(int& i = cur[u]; i; i = edges[i].next){ int v = edges[i].v, d; if((!vis[v]) && dis[v] == dis[u] + edges[i].cost && (d = dfs(v, min(flow - ret, edges[i].cap - edges[i].flow), cost))){ ret += d; edges[i].flow += d; edges[i ^ 1].flow -= d; cost += edges[i].cost * d; if(flow == ret) return flow; } } vis[u] = false; return ret; } void dinic(){ while(SPFA()){ int cost = 0; maxflow += dfs(s, INF, cost); mincost += cost; } } }
V.上下界网络流:
现在我们在普通网络流的基础上再给每条边增加一个属性:流量上界,即经过一条边的流量至少要大于等于流量下界。
1.无源汇上下界可行流:
对于一张
本文作者:Little_corn
本文链接:https://www.cnblogs.com/little-corn/p/18155070
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步