【Luogu P3376】网络最大流
2019-11-30 11:29
1806 查看
Luogu P3376
最大流是网络流模型的一个基础问题。
网络流模型就是一种特殊的有向图。
概念:
- 源点:提供流的节点(入度为0),类比成为一个无限放水的水厂
- 汇点:接受流的节点(出度为0),类比成为一个无限收水的小区
- 弧:类比为水管
- 弧的容量:类比为水管的容量;用函数\(c(x,y)\)表示弧\((x,y)\)的容量
- 弧的流量:类比为当前在水管中水的量;用函数\(f(x,y)\)表示弧\((x,y)\)的流量
- 弧的残量:即容量-流量
- 容量网络:对于一个网络流模型,每一条弧都给出了容量,则构成一个容量网络。
- 流量网络:对于一个网络流模型,每一条弧都给出了流量,则构成一个流量网络。
- 残量网络:对于一个网络流模型,每一条弧都给出了残量,则构成一个残量网络。最初的残量网络就是容量网络。
对于网络流模型\(G=(V,E)\)(\(V\)为点集,\(E\)为边集)有如下性质:
- 流量守恒:除了源点与汇点之外,流入任何节点的流一定等于流出该节点的流
- 容量限制:\(\forall (x,y) \in E,有0<=f(x,y)<=c(x,y)\)
- 斜对称性:\(\forall (x,y) \in E,有f(x,y)=-f(y,x).\)类似于函数奇偶性中的奇函数,或者是矢量的方向。
最大流问题,用通俗的方式解释就是从源点S到汇点T输送流量,询问最多有多少流量能输送到汇点。
对于这样的问题,我们引入一些新概念:
- 增广路:一条从源点到汇点的路径\(R\),满足\(\forall (x,y) \in S, c(x,y)-f(x,y)>=0.\)即残量非负
- 最大流最小割定理:网络流模型达到最大流,当且仅当残量网络中没有任何增广路(并不完整,但是足够了)
\(Ford-Fulkerson\)方法:每一次寻找一条增广路径。根据木桶原理,该增广路的最大流量\(f_{max}<=min(c(x,y)-f(x,y))\)。据此从源点发送流量至汇点并修改路径上所有弧的残量,直到无法找到增广路为止。
\(Edmons-Karp\)算法:基于\(Ford-Fulkerson\)方法的一种算法,核心就是利用\(BFS\)搜索源点到汇点的最短增广路,根据\(Ford-Fulkerson\)方法修改残量网络。复杂度最坏是\(O(nm^2)\)
所以其实我们在求最大流相关问题时,其实只利用到了残量网络,流量和容量一般并不需要记录。
关键点:有时候在求最大流时我们可能需要缩减一条边的流量,所以我们引入了反向边。当我们选用了一条反向边时,相当于缩减正向边的流量。很容易发现反向边的残量等于正向边的流量(最多恰好抵消正向流量)。
这样就能保证算法的正确性。
#include<cstdio> #include<algorithm> #include<queue> #include<cstring> using namespace std; struct data { int to,next,val; }e[2*100005]; int cnt,head[10005],prep[10005],pree[10005],flow[10005],ans; queue<int> que; int n,m,s,t,u,v,w; void add(int u,int v,int w) { e[++cnt].to=v; e[cnt].next=head[u]; head[u]=cnt; e[cnt].val=w; } int bfs(int s,int t) { while (!que.empty()) que.pop(); flow[s]=0x3f3f3f3f;//flow记录的是在增广路上经过该点的流量 que.push(s); for (int i=1;i<=n;i++) { prep[i]=-1;//用于记录前驱节点 pree[i]=0;//用于记录前驱边的编号 } prep[s]=0; while (!que.empty()) { int now=que.front(); que.pop(); if (now==t) break; for (int i=head[now];i;i=e[i].next) { if (e[i].val>0&&prep[e[i].to]==-1) { que.push(e[i].to); flow[e[i].to]=min(flow[now],e[i].val); pree[e[i].to]=i; prep[e[i].to]=now; } } } if (prep[t]!=-1) return flow[t]; else return -1; } void EK(int s,int t) { int delta=bfs(s,t);//寻找最短增广路的最大流量 while (delta!=-1) { ans+=delta; for (int j=t;j;j=prep[j]) { e[pree[j]].val-=delta; e[pree[j]^1].val+=delta; //链式前向星存边从编号2开始存储可以通过异或1快速取得反向边的编号。 } delta=bfs(s,t); } } int main() { scanf("%d%d%d%d",&n,&m,&s,&t); cnt=1; for (int i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&w); add(v,u,0); add(u,v,w); //加入正反边 } EK(s,t); printf("%d",ans); return 0; }
相关文章推荐
- luogu P3376 【模板】网络最大流(no)ek
- 【国家集训队2011】happiness 网络最大流
- 欧洲进行规划最大网络压力测验:29个国家参加
- hdu 1532 网络最大流
- 【COGS】1325 [ZJOI2010] 网络扩容 最大流+费用流
- 史上最大CPU缺陷Meltdown融毁和Spectre幽灵来袭,各网络设备厂家反馈以及解决方案汇总
- POJ 3436 ACM Computer Factory(最大流 残留网络找边)
- 网络最大流-模板
- 全球最大CDN服务商:中国网络攻击量世界第一
- POJ 3281 Dining 匹配,网络最大流
- 【2017青岛网络赛】1009 Smallest Minimum Cut hdu6214 最小割 最大流模版
- 洛谷 P3376 【模板】网络最大流
- POJ 1459 & ZOJ 1734 Power Network (网络最大流)
- 无线传感网络中最小功率路由与最大剩余能量的研究
- 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 L题 非递减权值最大
- POJ 1637 Sightseeing tour (混合图欧拉回路,网络最大流)
- poj 2391 二分 拆点 最大值最小值网络流
- 最大网络流Dinic算法(逆序广搜构造分层网络)
- 根据ip地址和掩码求网络地址,主机号,广播号和主机最大数。。
- 【最大流】【费用流】bzoj1834 [ZJOI2010]network 网络扩容