最大流模板(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 ...
随机推荐
- 练习_请使用日期时间相关的API
练习_请使用日期时间相关的API 练习:请使用日期时间相关的APi,计算出一个人已经出生了多少天.分析:1.使用scanner类中的方法next,获取出生日期2.使用DateFormat类中的方法pa ...
- SqlServer服务中利用触发器对指定账户进行登录ip限制提升安全性
转眼间上次写文章已经是 2022年12月15日的事情啦,本来从2022年7月份开始写作之后保持着每周一篇,然而从12月15日后断更了这么久,经历了,隔离.阳.过年.从今天开始继续坚持写作,本片文章给大 ...
- 【笔记向】RESTful api
RESTful api 是什么 源自论文:点我,中文版 Representational state transfer: Representational:数据表现形式 state:状态 transf ...
- 学习Java Day19
今天学习了包(package)将类组织在一个集合里,知道了如何导入类.
- ctfshow_web入门 sql注入(web171~248)
sql注入 这是算是学习+做题+记录的一个笔记吧,而且基本都是看着Y4师傅的博客做的 由于是做过sqli靶场,所以这个就记录快点了.如果靶场没遇到的,也会做笔记. union 联合注入 web171 ...
- CF335F Buy One, Get One Free
\(\text{Solution}\) 其实不想写(因为不好写... 所以贴贴 \(\text{Solution}\) 然而就关于这题而言讲得也不太清楚 可撤销贪心就是维护当前状态的最优解,同时考虑以 ...
- 【ASP.NET Core】标记帮助器——替换元素名称
标记帮助器不仅可以给目标元素(标记)插入(或修改)属性,插入自定义的HTML内容,在某些需求中还可以替换原来标记的名称. 比如我们在使用 Blazor 时很熟悉的 Component 标记帮助器.在 ...
- CSS 子代选择器(>)
后代选择器 后代选择器?是一种多个用空格分隔的选择器,别称包含选择器.范围是当前节点的所有子节点,包括其直接子节点. div#app下的所有 div 元素都使用下面的样式: div#app div { ...
- Vue学习笔记之计算属性、内容分发、自定义事件
1. 计算属性 计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数:简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化 ...
- Java/.Net双平台核心,Jvm和CLR运行异同点
前言: 本篇以.Net 7.0.2 CLR 和 OpenJDk19参照,解析下它们各自调用函数的异同. 以下为个人理解. 概述 JDK大约5.9G,CLR大约7.6G,两者相差1.7G左右. root ...