一、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手动模拟即可理解,每次走过时记得更新残余网络。

最新文章

  1. CQRS\ES架构介绍
  2. 【File】递归删除文件夹中子级文件/夹,并删除文件夹
  3. 免费好用的web应用托管平台
  4. mysql事务与mysql储存引擎
  5. Enterprise Library 5.0 系列教程
  6. c语言编程之双向循环链表
  7. WeX5是主要进行app开发吗?能开发微信App吗?
  8. 获取GridView的BoundField值
  9. 微信中QQ表情的解析(php)
  10. PHP的魔术方法(简介)
  11. python——时间与时间戳之间的转换
  12. [Linux] deepin与nginx
  13. hihocoder 1175
  14. 我的 Putty 配色方案
  15. springcloud采坑--Zuul上传文件报java.nio.charset.IllegalCharsetNameException: UTF-8;boundary=sqgzzmMxl1UPdIp0IAYnQgUIAr9yNewVAzKIX
  16. vue-cli环境配置
  17. luogu 1268 树的重量
  18. 实习培训——Java多线程(9)
  19. IDA 逆向工程 反汇编使用
  20. SPRING 集成 KAFKA 发送消息

热门文章

  1. 大数据实时多维OLAP分析数据库Apache Druid入门分享-下
  2. Flutter入门资料推荐
  3. 【新晋开源项目】内网穿透神器[中微子代理] 加入 Dromara 开源社区
  4. VS针对Linux远程调试步骤
  5. 11月29日内容总结——SQL注入问题、视图、触发器、事务、存储过程、函数、流程控制、索引、慢查询、数据库三大范式
  6. Grafana 系列文章(十三):如何用 Loki 收集查看 Kubernetes Events
  7. 微信小程序开卡步骤采坑过程艰难
  8. C++_虚函数
  9. jupyter环境搭建
  10. xampp修改mysql数据库密码(测试成功)