网络流的认识

news/2024/10/30 12:57:59/文章来源:https://www.cnblogs.com/high-sky/p/18515629

网络流的认识

什么是流网络

网络(network)是指一个特殊的有向图 \(G = (V,E)\),其与一般有向图的不同之处在于有容量和源汇点,不考虑反向边。
其中,我们有以下变量来方便表示:

  • \(S\):源点
  • \(T\):汇点
  • \(c(u,v)\):表示从 \(u\)\(v\) 这条有向边的容量\(c(u,v)\).
  • \(f(u,v)\):表示从 \(u\)\(v\) 这条有向边的流量\(f(u,v)\).

没有网络连接到洛谷图床

\[\text{图 } 1 \]

如上图,这就是一个流网络,其中 \(c(1,3)=4\) 表示的就是 \(1\)\(3\) 的容量为 \(4\),源点 \(S\) 往汇点 \(T\) 进行流水操作,其中 \(S\)\(T\) 能容下水的量是无限量的。(这里的水只是打个比方,因为很像自来水工厂为我们供水)。

什么是可行流

可行流,通俗点讲,就是在每条变分配流水的多少,使能满足条件(这个在生活实际也能推出)。
条件显然为以下:

  • 流量限制:\(0\leq f(u,v)\leq c(u,v)\),你这条水管的流量如果大于容量,后果不堪设想。
  • 流量守恒:抽象点讲,也就是你当前的点为 \(u\),入点为 \(p_1,p_2,\dots,p_{k1}\),出点分别为 \(q_1,q_2,\dots,q_{k2}\),那么显然:

\[\sum_{i=1}^{i\leq k1}f(p_i,u)=\sum_{i=1}^{i\leq k2}f(u,q_i) \]

形象点讲,也就是我当前流入到这个点的水的量最终都会流出到我可以到的点。

我们用 \(f\) 表示一个可行流,如下图:

有网络连接到洛谷图床

\[\text{图 } 2 \]

其中在 \(1\)\(3\) 这条边上,\(f(1,3) = 2\)\(c(1,3) = 4\),显然满足条件:\(0\leq f(1,3) = 2\leq 4 = c(1,3)\).
你可以试试看,能否满足第二个条件?

什么是最大流

最大流(也称最大可行流)实际是在可行流中找一个方案,使得流入汇点 \(T\) 的水的量最大。我们用 \(|f|\) 表示 \(S\)\(T\) 点流量总和。根据定义显然有下种公式:

\[|f| = \sum_{(u,v)\in E} f(u,v) - \sum_{(u,v)\in E} f(v,u). \]

在这里,右边的式子的第二个单项式 \(\sum_{(u,v)\in E} f(v,u)\) 可以忽略不计,为了严谨,考虑了反向边的情况。

What is 残留网络

概念和构建

残留网络总是针对原图 \(G =(V,E)\) 中的某一个可行流而言,因此,可以将残留网络看成是可行流的一个函数,通常记为 \(G_f\).
\(G_f = (V_f,E_f)\),其中 \(V_f =V\)\(E_f = E\)\(E\) 中所有的反向边。
残留网络中的容量记为 \(c'(u,v)\),且 \((u,v) \in E,(v,u) \in E\),定义为:

\[c'(u,v) = \left\{\begin{matrix} c(u,v) - f(u,v)\quad (u,v)\in E\\ f(v,u) \quad (u,v)\in E \end{matrix}\right. \]

作用

可以通过 增广路径 的配合找到更大的流,使最后图中的最大流最大。

增广路径

定义

如果从源点 \(S\) 出发沿着残留网络中容量大于 \(0\) 的边走,可以走到汇点 \(T\),那么将走过的边所组成的路径称为增广路径。
在这里我们发现:原网络可行流+残留网络可行流也是原网络的一个可行流
抽象点说(正式点说),\(f+f'\) 属于 \(G\) 的一个可行流,且有:

\[|f + f'| = |f| + |f'| \]

在网络中定点的一个划分,把所有顶点分成两个集合 \(S\)\(T\),其中 \(S\in S,T\in T\),而且有 \(S\cup T=V,S\cap T=\emptyset\),记为 \([S,T]\).

割的容量

指连接两个点集的边的容量总和,即 \(c(S,T)=\sum_{u\in S}\sum_{v\in T}c(u,v)\)

割的流量

指指连接两个点集的边的流量总和,
由上同理可得:

\[f(S,T) = \sum_{u\in S}\sum_{v\in T}(c(u,v)-c(v,u)) \]

有反向边时,\(c(v,u)\) 才有确值。
显然:

\[0\leq f(S,T)\leq c(S,T) \]

最小割

\(G\) 中所有割组成的集合中,容量最小的元素。

最大流最小割定理

以下 \(3\) 个,知 \(1\)\(2\)

  • \(1\)\(f\) 是最大流
  • \(2\)\(G_f\) 不存在增广路
  • \(3\)\(∃[S,T]\),满足 \(|f|=c(S,T)\)\(∃\)表示存在一个)。

证明:

  • 证明 \(1\rightarrow 2\)
    反证即可,若存在增广路就会使得当前的 \(f\) 不是最大流,也就是 \(|f| + |f'|>|f|\),由条件又可知道:\(|f|\) 最大,所以说当 \(G_f\) 不存在增广路时,\(f\) 为最大流。
  • 证明 \(2\rightarrow 3\)
    我们将对于 \(G_f\) 中从 \(S\) 出发沿着容量大于 \(0\) 的边可以到达的点全部放入集合 \(S\) 中,然后令 \(T = V - S\),那么对于点 \(x\in S,y\in Y\),边 \((x,y)\) 必有 \(f(x,y) = c(x,y)\)
  • 证明 \(3\rightarrow 1\)
    因为 \(|f|\leq \text{最大流}\leq c(S,T)\),而由 \(3\) 可知 \(|f|=c(S,T)\),故上式取等,即 \(f\) 是最大流。

求最大流

基于上述定理,我们可以不断寻找增广路,利用增广路更新残留网络,直到找不到增广路,即可求得最大流。

EK 算法

时间复杂度 \(O(nm^2)\)

graph TD A[拿到原图] -->|改图| B(残留网络) B --> C(找增广路) C --> d{是否存在增广路到达 T} d -->|是| D[更新残留网络] D --> |继续寻找|C d -->|否| E[找到最大流] E --> F[输出]

Code1

#include<iostream>
#include<cstring>
using namespace std;const int INF=1e9;
const int N=1005, M=10010;
int n, m, S, T;
struct node{int to, c, next;
}e[M<<1];
int h[N], tot;// 残量网络建图,初始时正向的容量是 c, 反向容量是 0 。
void add(int u, int v, int c){e[tot].to=v, e[tot].c=c, e[tot].next=h[u], h[u]=tot++;e[tot].to=u, e[tot].c=0, e[tot].next=h[v], h[v]=tot++;	
}int lim[N], pre[N]; // lim[u] 表示 S 到点 u 路径容量的最小值, pre[u] 表示 u 的前驱边。
bool vis[N];
int q[N];// bfs 找增广路。
bool bfs(){memset(vis, false, sizeof vis);int hh=0, tt=-1;q[++tt]=S, vis[S]=true, lim[S]=INF;while(tt>=hh){int hd=q[hh++];for(int i=h[hd]; ~i; i=e[i].next){int go=e[i].to;if(vis[go] || !e[i].c) continue;vis[go]=true, q[++tt]=go;lim[go]=min(lim[hd], e[i].c);pre[go]=i;if(go==T) return true;}}return false;
}int EK(){int res=0;while(bfs()){res+=lim[T];for(int i=T; i!=S; i=e[pre[i]^1].to){e[pre[i]].c-=lim[T], e[pre[i]^1].c+=lim[T];}}return res;
}
int main(){memset(h, -1, sizeof h);cin>>n>>m>>S>>T;while(m--){int u, v, c; cin>>u>>v>>c;add(u, v, c);}	cout<<EK()<<endl;return 0;
}

Code2

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstring>
#define N 1007
#define M 10007
#define int long long
using namespace std;
const int INF = 1e9 + 7;
struct node{int to,val,nxt;
}e[M << 1];
int n, m, S, T, tot;
int head[N],dis[N],pre[N];
bool vis[N];
queue<int> q;
void add(int a,int b,int c) {e[tot].to = b, e[tot].val = c, e[tot].nxt = head[a], head[a] = tot++;e[tot].to = a, e[tot].val = 0, e[tot].nxt = head[b], head[b] = tot++;
}
bool bfs() {while(!q.empty()) q.pop();memset(vis,false,sizeof vis);q.push(S), vis[S] = true, dis[S] = INF;while(!q.empty()) {int t = q.front();q.pop();for (int i = head[t];i != -1;i = e[i].nxt) {int v = e[i].to;if (!vis[v] && e[i].val) {vis[v] = true;dis[v] = min(dis[t],e[i].val);pre[v] = i;if (v == T) return true;q.push(v);}}}return false;
}
int EK(){int r = 0;while(bfs()) {r += dis[T];for (int i = T;i != S;i = e[pre[i] ^ 1].to)e[pre[i]].val -= dis[T], e[pre[i] ^ 1].val += dis[T];}return r;
}signed main(){cin >>n >> m >> S>> T;memset(head, -1,sizeof head);for(;m--;) {int a,b,c;cin >> a >> b >> c;add(a,b,c);}cout << EK();return 0;
}

Dinic 算法

多路增广,时间复杂度 \(O(n^2m)\)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define gc() (st==ed&&(ed=(st=buf)+fread(buf,1,100000,stdin),st==ed)?EOF:*st++)
char buf[100001],*st=buf,*ed=buf;
void read(int &a){a=0;char c=gc();while(c>'9'||c<'0')c=gc();while(c>='0'&&c<='9')a=a*10+c-48,c=gc();
}const int INF=0x3f3f3f3f;
const int N=10010, M=1e5+5;struct node{int to, c, next;
}e[M<<1];
int h[N], tot;void add(int u, int v, int cap){e[tot].to=v, e[tot].c=cap, e[tot].next=h[u], h[u]=tot++;e[tot].to=u, e[tot].c=0, e[tot].next=h[v], h[v]=tot++;  
}int n, m, S, T;int d[N], q[N], cur[N];bool bfs(){memset(d, -1, sizeof d);int tt=-1, hh=0;q[++tt]=S, d[S]=0, cur[S]=h[S];while(tt>=hh){int hd=q[hh++];for(int i=h[hd]; ~i; i=e[i].next){int go=e[i].to;if(d[go]==-1 && e[i].c){d[go]=d[hd]+1;cur[go]=h[go];if(go==T) return true;q[++tt]=go;}}}return false;
}int find(int u, int limit){if(u==T) return limit;int flow=0;for(int i=cur[u]; ~i && flow<limit; i=e[i].next){cur[u]=i;int go=e[i].to;if(d[go]==d[u]+1 && e[i].c){int t=find(go, min(e[i].c, limit-flow));if(!t) d[go]=-1;e[i].c-=t, e[i^1].c+=t, flow+=t;}}return flow;
}int dinic(){int res=0, flow;while(bfs()) while(flow=find(S, INF)) res+=flow;return res;
}signed main(){memset(h, -1, sizeof h);read(n), read(m), read(S), read(T);while(m--){int u, v, cap; read(u), read(v), read(cap);add(u, v, cap);}cout<<dinic()<<endl;return 0;
}

完结。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/824103.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CF370

废话370:纪念盗笔青春提交记录几个脑残错误后文会提到 3.题目: 黄黄绿蓝蓝( 幸好 370 不是“红红红红红” | “黑黑黑黑黑” ) 算法: 是没有滴 贪心,前缀和 正题 CF370A Rook, Bishop and King 签到数学题 车可以两步到达任意点 ,只需判断出发点与目标点是否在同行 | 同…

那两天,我的灵魂缺失了

写在前面 261 字 | 思念 | 回忆 | 爱恋 | 悔恨 | 执念 | 断舍离 | 放弃 For Nileicna. 正文我的灵魂每一天都在游走。6 月 8 日的下午 17:00,吹过一阵风,带走我的身体。我的灵魂停留在原地。我跟很多人说,我不认识你。那些时候,我的灵魂总是寄存在十字架上。自那天之后,每…

轻松上手CANoe Scenario Editor———智能网联工程师入门篇

(小编先带大家扫盲一下) V2X(Vehicle-to-Everything,车与万物通信)是一种先进的通信技术,使车辆能够与周围环境进行信息交换。这不仅包括与其他车辆(V2V)的互动,还涵盖与基础设施(V2I)和行人(V2P)的通信。通过V2X,车辆能够实时获取周围信息,从而提升行驶安全性和…

Windows Server 2016 中文版、英文版下载 (updated Oct 2024)

Windows Server 2016 中文版、英文版下载 (updated Oct 2024)Windows Server 2016 中文版、英文版下载 (updated Oct 2024) Windows Server 2016 Version 1607 请访问原文链接:https://sysin.org/blog/windows-server-2016/ 查看最新版。原创作品,转载请保留出处。 作者主页:…

Windows 7 Windows Server 2008 R2 简体中文版下载 (updated Oct 2024)

Windows 7 & Windows Server 2008 R2 简体中文版下载 (updated Oct 2024)Windows 7 & Windows Server 2008 R2 简体中文版下载 (updated Oct 2024) Windows 7 & Windows Server 2008 R2 (2024 年 10 月更新) 请访问原文链接:https://sysin.org/blog/windows-7/ 查…

SA:从入门到入土

基本应用 读入一个长度为 $ n $ 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序(用 ASCII 数值比较)从小到大排序。 解法 1.将每个后缀取出来,直接排序 \(O(n^2 \log n)\) 2.用hash二分LCP比较下一位,\(O(n \log^2 n)\) 3.倍增求后缀数组,\…

06.动态代理设计模式

06.动态代理设计模式 目录介绍01.为何要动态代理1.1 为何要动态代理 1.2 动态代理思考02.动态代理的概念2.1 动态代理定义 2.2 动态代理类比理解 2.3 动态代理参与者 2.4 动态代理步骤03.动态代理的实现3.1 罗列一个场景 3.2 用一个例子理解代理 3.3 基于接口动态代理 3.4 基于…

.NET 8.0 开源在线考试系统(支持移动端)

https://www.cnblogs.com/1312mn/p/18510576阅读目录前言 系统介绍 系统功能 支持环境 系统源码 项目部署 项目效果 项目总结 项目地址 最后前言 推荐一款基于.NET 8.0 免费开源跨平台在线考试系统,系统不仅支持桌面端,还特别优化了移动端的用户体验。 通过本系统可以轻松搭建…

GaussDB数据计算路由层(Coordinator)关键技术方案

GaussDB Kernel V5版本的Catalog还是本地存储, 所以还需要考虑catalog的持久化问题.未来演进元数据解耦,Coordinator 无状态, 就不需要考虑Catalog持久化问题了。但是跨节点场景下的事务提交在Coordinator上还是要持久化的。图14 Coordinator模块图 路由信息:每个表数据共分1…

GaussDB全局事务管理层(GTM)关键技术方案

GTM 仅处理全局时间戳请求, 64位CSN递增,几乎都是CPU ++和消息收发操作。不是每次都写ETCD, 而是采用定期持久化到ETCD 里, 每次写ETCD的CSN要加上一个backup_step (100w), 一旦GTM故障,CSN从ETCD读取出来的值保证单调递增。当前GTM 只完成CSN++, 预估可以支持200M/s 请求…

GaussDB集群管理层(CM)关键技术方案

GaussDB Kernel V5 集群管理层关键模块如下。图4 集群管理层组件设计图 CM 组件提供了四种服务 CM Agent, CM Server, OM Monitor, cm_ctl,与各类实例服务组件(CN, DN, GTM 等)一起构成了整个数据库集群系统。cm_ctl通过命令行执行集群的启动、停止、状态查询、主备倒换、备…

2024年10月中国数据库排行榜:TiDB续探花,GaussDB升四强

10月墨天轮排行榜解读已发布!OceanBase、PolarDB、TiDB三甲格局稳定,GaussDB排名攀升至第四,此外亦有部分产品表现亮眼,一起来看更多排名情况与解读。10月中国数据库流行度排行榜如期发布,再次印证了市场分层的加速形成。国家数据库测评结果已然揭晓,本批次通过的产品数量…