EK算法求最大流
题目
【模板】网络最大流
题目描述
如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。
输入格式
第一行包含四个正整数 ,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来 行每行包含三个正整数 ,表示第 条有向边从 出发,到达 ,边权为 (即该边最大流量为 )。
输出格式
一行,包含一个正整数,即为该网络的最大流。
样例 #1
样例输入 #1
4 5 4 3 4 2 30 4 3 20 2 3 20 2 1 30 1 3 40
样例输出 #1
50
提示
样例输入输出 1 解释
题目中存在 条路径:
- ,该路线可通过 的流量。
- ,可通过 的流量。
- ,可通过 的流量(边 之前已经耗费了 的流量)。
故流量总计 。输出 。
数据规模与约定
- 对于 的数据,保证 ,。
- 对于 的数据,保证 ,,。
代码
// 最大流最小割定理:(1) 可以流f是最大流(2) 可行流f的残留网络中不存在增广路(3) 存在某个割[S, T],|f| = c(S, T) //EK算法基于 可行流f的残留网络中不存在增广路 #include<bits/stdc++.h> #define pii pair <int, int> #define pll pair <ll, ll> #define endl '\n' #define il inline #define pb push_back #define fi first #define se second #define lc u<<1 #define rc u<<1|1 using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; const int N=2e2+10,M=1e4+10; int h[N],e[M],ne[M],f[M],idx;//前向星,f表示容量 int n,m,S,T;//点数边数,起点终点 int q[N],d[N],pre[N];//q:找增广路时宽搜所用队列,d[i]:走到i点时流量的限制,pre记录前驱边,用于更新残留网络 bool st[N];//防止重复搜索 void add(int a,int b,int c) { e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;//加入正向边,存储容量 e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;//加反向边,初始流量为0 } void remake() { }; bool bfs() { int hh=0,tt=0;//宽搜初始化 memset(st,false,sizeof st); q[0]=S,st[S]=true,d[S]=INF;//起点没有限制 while(hh<=tt) { int t=q[hh++]; for(int i=h[t];~i;i=ne[i]) { int ver=e[i]; if(!st[ver]&&f[i])//没有访问过并且流量大于0 { st[ver]=true;//标记 d[ver]=min(d[t],f[i]);//更新容量限制 pre[ver]=i;//记录前驱边 if(ver==T)return true;//找到增广路则返回 q[++tt]=ver; } } } return false; } ll EK() { ll r=0; while(bfs())//如果存在增广路 { r+=d[T];//增加流量 for(int i=T;i!=S;i=e[pre[i]^1])//依次更新前驱边的流量 f[pre[i]]-=d[T],f[pre[i]^1]+=d[T]; } return r;//返回最大流 } int main() { cin>>n>>m>>S>>T; memset(h,-1,sizeof h); while(m--) { int a,b,c; cin>>a>>b>>c; add(a,b,c); } cout<<EK()<<endl; return 0; }
一个菜鸡
本文作者:Avarice_Zhao
本文链接:https://www.cnblogs.com/avarice/p/16448820.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步