最大流模板(EK,Dinic
一、EK
EK算法:用bfs找增广路直到找不到为止。找到则更新最大流和残余网络,找不到则结束。
残余网络:对于一条走过的边,其正向边权值减少相应值,反向边权值增加相应值(用于反悔)。
增广路:从所求起点到终点之间还可以增大流量的路径。
复杂度O(n*m^2)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m,s,t;
const int maxn=220;
ll G[maxn][maxn],flow[maxn],pre[maxn];//flow:源点到当前点的流量,pre增广路的上一条边
ll bfs(int s,int t){//找增广路
queue<int>qu;
while(!qu.empty())qu.pop();
memset(pre,-1,sizeof pre);//记录前驱
pre[s]=0;
flow[s]=0x3f3f3f3f;
qu.push(s);
while(!qu.empty()){
int p=qu.front();qu.pop();
if(p==t)break;
for(int i=1;i<=n;i++){
if(i!=s&&G[p][i]>0&&pre[i]==-1){
pre[i]=p;
flow[i]=min(flow[p],G[p][i]);//选承载量最小的
qu.push(i);
}
}
}
if(pre[t]==-1)return -1;
return flow[t];
}
ll EK(int s,int t){
ll ans=0,tot=0;
while(1){
ans=bfs(s,t);
if(ans==-1)break;
int p=t;
while(p!=s){//回溯整条增广路,进行更新
G[pre[p]][p]-=ans;
G[p][pre[p]]+=ans;//反向边
p=pre[p];
}
tot+=ans;
}
return tot;
}
int main()
{
int i,j;
cin>>n>>m>>s>>t;
memset(G,0,sizeof G);
memset(flow,0,sizeof flow);
for(i=0;i<m;i++){
int a,b;ll c;cin>>a>>b>>c;
G[a][b]+=c;//累计容量 防止重边
}
cout<<EK(s,t);
return 0;
}
二、Dinic
有时候EK会超时 因为可能会出现增广路经过的其中一条边值为1,而其他边值很大的情况,则需要一直增广。
而Dinic利用分层可以一次dfs实现多次增广,从而优化EK算法。
Dinic算法:先利用bfs进行分层(只能往层数+1的地方走),再利用dfs实现进行增广(一次dfs实现多次增广)。该步骤一直循环直到不可分层为止。
复杂度O(m*n^2)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 50005;
const int maxm=500010;//边
const int inf =0x3f3f3f3f;
int head[maxn],dis[maxn];
struct Edge
{
int to,next,f;
}edge[maxm]; //链式前向星
int s,t,cnt;
void add(int u,int v,int f)
{
edge[cnt].to=v;
edge[cnt].f=f;
edge[cnt].next=head[u];
head[u]=cnt++; //正向建边//相邻边则为反向边,cnt从0开始(1不行)
edge[cnt].to=u;
edge[cnt].f=0;
edge[cnt].next=head[v];
head[v]=cnt++; //反向建边
}
bool bfs()
{
memset(dis,-1,sizeof(dis));
queue <int> que;
dis[s]=0;
que.push(s);
while(!que.empty())
{
int u=que.front();
que.pop();
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
int f=edge[i].f;
if(dis[v]==-1&&f>0)//有流量且未访问过
{
dis[v]=dis[u]+1;//分层
if(v==t) return true;
que.push(v);
}
}
}
return false;
}
int dfs(int x,int maxf) //maxf表多少流量流到当前节点
{
if(x==t||maxf==0) return maxf;
int flow=0;
for(int i=head[x];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
int f=edge[i].f;
if(dis[v]==dis[x]+1&&f>0)
{
f=dfs(v,min(f,maxf-flow));//当前边的容量和该点剩余量取min
edge[i].f-=f;
edge[i^1].f+=f;//相邻边则为反向边,通过异或可以直接找到反向边
flow+=f;
if(flow==maxf) return flow;
}
}
return flow;
}
int main()
{
int T,n,m,k;
cin>>n>>m>>s>>t;
cnt=0;
memset(head,-1,sizeof(head));
for(int i=0;i<m;i++)
{
int u,v,f;
scanf("%d%d%d",&u,&v,&f);
add(u,v,f); //加边
}
int ans=0;
while(bfs()) ans+=dfs(s,inf);
cout<<ans<<endl;
}
经过bfs分层后有123三层,从s出发,只会往第二层的三个点依次进行dfs。dfs手动模拟即可理解,每次走过时记得更新残余网络。
最大流模板(EK,Dinic的更多相关文章
- 图论算法-网络最大流【EK;Dinic】
图论算法-网络最大流模板[EK;Dinic] EK模板 每次找出增广后残量网络中的最小残量增加流量 const int inf=1e9; int n,m,s,t; struct node{int v, ...
- 【Luogu】P3376网络最大流模板(Dinic)
最大流模板成为另一个被攻克的模板题. 今天QDC给我讲了一下Dinic,感觉很好懂.于是为了巩固就把这道题A掉了. 核心思想就是不断BFS分层,然后不断DFS找增广路.找不到之后就可以把答案累加输出了 ...
- 「模板」网络最大流 FF && EK && Dinic && SAP && ISAP
话不多说上代码. Ford-Fulkerson(FF) #include <algorithm> #include <climits> #include <cstdio& ...
- 算法学习笔记(8.1): 网络最大流算法 EK, Dinic, ISAP
网络最大流 目录 网络最大流 EK 增广路算法 Dinic ISAP 作者有话说 前置知识以及更多芝士参考下述链接 网络流合集链接:网络流 最大流,值得是在不超过管道(边)容量的情况下从源点到汇点最多 ...
- 【模板】最大流模板(dinic)
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- P3376 网络最大流模板(Dinic + dfs多路增广优化 + 炸点优化 + 当前弧优化)
### P3376 题目链接 ### 这里讲一下三种优化的实现以及正确性. 1.dfs多路增广优化 一般的Dinic算法中是这样的,bfs() 用于标记多条增广路,以至于能一次 bfs() 出多次 d ...
- 【模板】网络流-最大流模板(Dinic)
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> u ...
- 图论算法-最小费用最大流模板【EK;Dinic】
图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...
- 最大流的EK算法模板
模板题:洛谷p3376 题目大意: 给出一个网络图,以及其源点和汇点,求出其网络最大流. 基本思路: 套模板 EK的时间复杂度O(V*E^2) EK算法思路: 1.通过BFS拓展合法节点(每个节点在本 ...
- P3376 【模板】网络最大流( Edmonds-krap、Dinic、ISAP 算法)
P3376 [模板]网络最大流( Edmonds-krap.Dinic.ISAP 算法) 题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入格式 第一行包含四个正整数N.M.S ...
随机推荐
- 洛谷 P3916 图的遍历
题目链接 最容易想的思路:对于每一个点都进行dfs/bfs,时间复杂度为O(n*(n+m)),显然超时 可以使用类似记忆化的操作,一个点能到达的最大值是自己所有能达到的边的最大值,则可以递归来做 但有 ...
- 实现一个简单的在浏览器运行Dotnet编辑器
之前已经实现过Blazor在线编译了,现在我们 实现一个简单的在浏览器运行的编辑器,并且让他可以编译我们的C#代码, 技术栈: Roslyn 用于编译c#代码 [monaco](microsoft/m ...
- .NET遍历二维数组-先行/先列哪个更快?
上周在.NET性能优化群里面有一个很有意思的讨论,讨论的问题如下所示: 请教大佬:2D数组,用C#先遍历行再遍历列,或者先遍历列再遍历行,两种方式在性能上有区别吗? 据我所知,Julia或者pytho ...
- 断点调试/认证/权限/频率-源码分析/基于APIView编写分页/异常处理
内容概要 断点调试 认证/权限/频率-源码分析 基于APIView编写分页 异常处理 断点调试 # 程序以 debug模式运行,可以在任意位置停下,查看当前情况下变量数据的变化情况 # pycharm ...
- element el-table固定列凹陷问题
1.业务背景 列表显示字段过多,最后一栏操作列加固定显示,横向添加滚动条,在自测浏览器开发者模式时,发现固定列的最后一行出现了凹陷现象,网上查阅资料大多为在更新生命周期或者页面更新操作时重载页面,这些 ...
- 学习Java Day22
今天学习了如何在包中增加类,想要将包放入类中,就必须将包的名字放在源文件的开头,即放在定义这个包中各个类的代码之前
- 深度学习-LSTM
目录 前言 神经网络的历史和背景 循环神经网络的出现及其作用 LSTM在处理序列数据中的应用 LSTM的基本原理 LSTM的结构和原理 遗忘门.输入门.输出门的作用 LSTM的训练方法 代码 LSTM ...
- Blue Mary开公司
Blue Mary开公司 题面:[JSOI2008]Blue Mary开公司 题目大意: 每次加入一条形如 \(y=Px + S - P\) 的直线,询问 \(x=T\) 时此处最高的 \(y\) 值 ...
- 题解 [ZJOI2007]棋盘制作
把悬线法这个坑填了,还是很简单的 qwq. 悬线法一般解决有一定约束条件的最大矩形问题.悬线的定义是从一个点一直往上走直到边界或者不符合条件结束. 炒个例子,在这题里面比如说有这样一个矩形 0 1 0 ...
- Vue框架整理:computed计算属性设置与缓存
简单的一些小计算可以直接用模板内的表达式计算,比较复杂一点的就建议使用"计算属性来运算了",也方便后期的维护:vue所有的计算属性都以函数的形式写在Vue实例内的computed里 ...