网络流24题题解戳这里~

网络流基础概念


考虑这幅图,你可以看成从村庄s到村庄t有很多条物流道路,每个点都是个中转结点,每条路的权值即该条路最多能运送的货物

介绍一些基本概念:

网络:一个入度为0的点s,一个出度为0的点t,每条边有自己权值的有向图
容量:当前边上的权值,比如SA的容量即为3
源点:入度为0的点,通常s来表示
汇点:出度为0的点,通常t来表示
流:一个合法解称作一个流,也就是一条可以从源点到汇点的一条合法路径。
流量:每条边各自运送的包裹数称作其流量,最终收集的总数为整个流的流量。边上的流量:f(SA)=2,代表今天从s发了两个货物到A,最终整幅图每个流的流量和即为这张网络的总流量

显然我们会有两个定理
容量限制:每条边的流量不超过其容量(仓库塞不下这么多包裹)。
流量平衡:对于除源点和汇点以外的点来说,其流入量一定等于流出量。

割:一个边集,删掉这个边集即可使s与t不连通,比如说{C->T,S->A}即是一个割集,割集的大小即是边的容量和,这里为5
最小割:大小最小的割集
最大流:限制下能走到t的最大流量,即最终能送到t的最多包裹数

假设我们沿着S->A->C->T发包裹,因为容量限制的存在,我们最多发两个包裹,那么剩下的这幅容量图,即是我们的残量网络

增广路:即能增加运货量的s到t的路径

之前那幅图即有一条增广路:S->A->T

最大流-最小割

给出结论:最小割的容量等于最大流的流量
所以求最小割和最大流本质是一个问题,接下来说明最大流的求法

朴素想法

考虑这幅很小的简单图,我们显然可以用深搜的思想去暴力求解
假设增广路的流量为Δi\Delta{i}Δi ,那么显然最后的最大流f为 ∑i=1nΔi\sum_{i=1}^n{\Delta{i}}∑i=1n​Δi

这种算法没有错,但显然只适用于很小的图,才可以在时间限制内去找到所有的增广情况

FF算法(Ford-Fulkerson)

FF算法是在原图上通过建立后悔边的方法来加快dfs,哪怕一开始我们选择的路径是错误的,我们也可以通过后悔边不断去修正这个错误,以此达到最后正确的结果(把所有错误的情况修正了,就是正确的结果之一)

后悔边

我们一开始会对所有的有向边建一条反向的容量为0的边,这就是后悔边
同时后悔边有一个性质
在任意一个残量网络中,残量网络边上的容量+后悔边上的容量=这条边初始的容量

现在我们来看看后悔边是怎么生效的

我们可以看见,当我们沿着后悔边去走了一段达到了终点后,我们再次修改,就相当于把原来不该走的错误修正了,最后网络会进行正确的增广,这就是后悔边的作用

对于一幅残量网络,新找到的需要通过后悔边到达终点的路,相当于将原来后悔边所在处的路从原来的路径删去


假设回头的路是我们的后悔边,那么我们沿着后悔走上的那几段,都应该从之前找到的路径删去并更新网络,最后我们的图会变成正确的模样(比如上图我们一开始只找到三条直达路,但我们新找到了最下面那条很长弯曲的路,其中经过两条后悔边,那么我们从原来的网络删去这两段,最后网络会更新成右边正确的样子,即有四条路(假设路多就是最大流大))

那么现在我们显然发现了后悔边是能维护结果的正确性的,那么我们来实现FF

先回顾整个过程,我们最少得有两个函数

ll dfs(int v,int t,ll flow)//去找增广路
{if(v==t)//到达汇点返回return flow;used[v]=true;for(int i=0;i<G[v].size();i++)//遍历整幅图{edge &e=G[v][i];if(!used[e.to]&&e.cap>0)//下个结点未被访问过,并且这条路容量大于0就走{int d=dfs(e.to,t,min(flow,e.cap));if(d>0)//找到增广路{e.cap-=d;//容量-dG[e.to][e.rev].cap+=d;//反向边增加dreturn d;}}}return 0;//没有找到
}ll get_maxFlow(int s,int t)
{ll maxFlow = 0;for(;;){memset(used,0,sizeof(used));ll f=dfs(s,t,INF);//不断去找增广路if(f==0)return maxFlow;//找不到就返回,可以证明当找不到增广路的时候一定是正确的解maxFlow+=f;}
}

接下来贴完整的FF模板,请确保上面两个关键函数已经看懂了
我们采用邻接表的方式存图,请注意加边函数,因为每次存边的时候是正向和反向一起当做一组存的,所以我们可以通过size来判定对应的正向边或反向边(建议自己模拟操作理解下)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int maxn=205;struct edge{int to;//终点ll cap;//容量int rev;//反向边
};int n,m,s,t;
vector<edge> G[maxn];
bool used[maxn];//dfs中用到的访问标记void add_edge(int from,int to,ll cap){G[from].push_back((edge){to,cap,G[to].size()});G[to].push_back((edge){from,0,G[from].size()-1});
}ll dfs(int v,int t,ll flow)//去找增广路
{if(v==t)//到达汇点返回return flow;used[v]=true;for(int i=0;i<G[v].size();i++)//遍历整幅图{edge &e=G[v][i];if(!used[e.to]&&e.cap>0)//下个结点未被访问过,并且这条路容量大于0就走{int d=dfs(e.to,t,min(flow,e.cap));if(d>0)//找到增广路{e.cap-=d;//容量-dG[e.to][e.rev].cap+=d;//反向边增加dreturn d;}}}return 0;//没有找到
}ll get_maxFlow(int s,int t)
{ll maxFlow = 0;for(;;){memset(used,0,sizeof(used));ll f=dfs(s,t,INF);if(f==0)return maxFlow;maxFlow+=f;}
}int main()
{ios::sync_with_stdio(false);cin>>n>>m>>s>>t;int u,v;ll w;while(m--){cin>>u>>v>>w;add_edge(u,v,w);}ll ans=get_maxFlow(s,t);cout<<ans<<endl;return 0;
}

可以在洛谷的网络流模板提交试试,会被卡掉两组数据,FF虽然简单易懂,但在顶点数或最大流量非常大师,这个算法就不够快了

Dinic算法

FF算法是通过深搜来找增广路,并沿着它进行增广。与之相对,dinic算法总数寻找最短的增广路(bfs来找),并沿着它增广。
因为最短增广路的长度在增广的过程中始终不会变短,所以我们不用每次都跑一遍bfs来找最短增广路。

这里引用分层图的概念

我们每一次跑一遍bfs,就可以构建一幅分层图,s为0,所有一步可达的点在层次1,两步可达的点在层次2,以此类推
我们在分层图上跑dfs,直到找不到新的增广路了,就说明最短增广路的长度确实变长了,我们就重新跑一遍bfs构造新的分层图

直到最后我们的汇点不在层次网络中,算法终止,我们就找到了最大流

PS:Dinic中有一个优化叫做当前弧优化
即每一次dfs增广时不从第一条边开始,而是用一个数组cur记录点u之前循环到了哪一条边,以此来加速

总代码如下,优化的地方已在代码中标出:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int maxn=250;struct edge{int to;//终点ll cap;//容量int rev;//反向边
};int n,m,s,t;
vector<edge> G[maxn];
int level[maxn];//距离标号
int iter[maxn];//iter就是记录当前点u循环到了哪一条边//连边函数,edge中的rev记录的是反向边在数组中的位置
void add_edge(int from,int to,ll cap)
{G[from].push_back((edge){to,cap,G[to].size()});G[to].push_back((edge){from,0,G[from].size()-1});
}void bfs(int s)//广搜构建分层图
{memset(level,-1,sizeof(level));//每跑一次bfs都要把之前的分层图清空queue<int> q;level[s]=0;//源点层次为0q.push(s);while(!q.empty()){int v=q.front();q.pop();for(int i=0;i<G[v].size();i++){edge e=G[v][i];if(level[e.to]<0&&e.cap>0)//只要这个点还未访问过并且能走{level[e.to]=level[v]+1;//那这一点就是上一点能一步到达的点q.push(e.to);}}}
}ll dfs(int v,int t,ll f)
{if(v==t)//到达汇点终止return f;for(int &i=iter[v];i<G[v].size();i++)//注意这里的&符号,这样i增加的同时也能改变iter[v]的值,达到记录当前弧的目的{edge &e=G[v][i];if(e.cap>0&&level[v]<level[e.to])//残量不为0并且满足分层图{ll d=dfs(e.to,t,min(f,e.cap));if(d>0){e.cap-=d;//正向边减流量G[e.to][e.rev].cap+=d;//反向边加流量return d;}}}return 0;//否则没有增广路,返回0
}ll dinic(int s,int t)
{ll flow=0;for(;;){bfs(s);if(level[t]<0)//汇点不在分层图中了就返回,找到最大流了return flow;memset(iter,0,sizeof(iter));//每一次建立完分层图后都要把iter置为每一个点的第一条边ll f;while((f=dfs(s,t,INF))>0){//找增广路flow+=f;}}
}int main()
{cin>>n>>m>>s>>t;int u,v;ll w;while(m--){cin>>u>>v>>w;add_edge(u,v,w);}ll ans=dinic(s,t);cout<<ans<<endl;return 0;
}

洛谷中提交能AC的

我会在我另一篇blog中记录网络流24题每题的题解和代码

网络流最大流(FF、Dinic)详解相关推荐

  1. Java stream流式计算详解

    Java stream流式计算详解 1. Stream概述 1.1 Stream简介 1.2 Stream分类 2. Stream操作 2.1 Stream创建 2.2 Stream无状态操作 2.3 ...

  2. 微商八大途径吸粉、引流客源技巧详解!

    微商八大途径吸粉.引流客源技巧详解! 2017年之后,微商在这个互联网黄金时代的背景下,正在继续发展壮大,从事微商的创业小伙伴们也越来越多.不过许多刚开始进入微商这一领域的小伙伴们都会有吸粉和引流方面 ...

  3. java IO流基础 万字详解(从拷贝文件到模拟上传头像)

    目录 一.前言: 二.IO流简介: 1.什么是IO流? 2.IO流能干什么? 3.IO流的分类: 4.IO流体系: 三.字符流读写文件: 1.普通字符流读取文件: 前言: ①以单个字符读取: 代码演示 ...

  4. 性能百万/s:腾讯轻量级全局流控方案详解

    作者:莫家文,腾讯事务型开发工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/320.html WeTest ...

  5. 性能百万/s:腾讯轻量级全局流控方案详解【转自Wetest】

    阿里用的方案是在nginx中配置限流(限流功能模块是自己开发的),流量统计线上是有监控打通的,具体的限流值是通过线上流量表现+线下性能测试(模拟线上场景)测试得出的. 全新的全局流控实现方案,既解决了 ...

  6. flink大数据处理流式计算详解

    flink大数据处理 文章目录 flink大数据处理 二.WebUI可视化界面(测试用) 三.Flink部署 3.1 JobManager 3.2 TaskManager 3.3 并行度的调整配置 3 ...

  7. TS流PAT/PMT详解

    原文 :http://www.cnblogs.com/shakin/p/3714848.html 一 从TS流开始 从MPEG-2到DVB,看着看着突然就出现了一大堆表格,什么PAT.PMT.CAT- ...

  8. 图论 —— 网络流 —— 最大流 —— FF 算法与 EK 算法

    [概述] FF 算法与 EK 算法是求解最大流的一般增广路方法,其时间复杂度均为 O(n*m*m) Ford-Fulkerson 算法是求解最大流的最基础的算法,其核心思想是增广路定理:网络达到最大流 ...

  9. GB28181 PS流传输格式详解

    1.PS流传输格式预览 1.视频关键帧的封装 RTP + PS header + PS system header + PS system Map + PES header +h264 data 2. ...

  10. C++流的streambuf详解及TCP流的实现

    前言 streambuf是C++流(iostream)与流实体(或者叫原始流,文件.标准输入输出等)交互的桥梁 # 文件流 fstream <--> filebuf <--> ...

最新文章

  1. Vlan 4096的限制原因
  2. 引子 我想大家应该都很熟悉DNS了,这回在DNS前面加了一个D又变成了什么呢?这个D就是Dynamic(动态),也就是说,按照传统,一个域名所对应的IP地址应该是定死的,而使用了DDNS后,域名所对应
  3. linux下搭建ntp服务,Linux 下快速搭建ntp 时间同步服务器
  4. 集成ffmpeg/x264:ERROR: libx264 not found的问题
  5. CodeVS 3027 线段覆盖2(DP)
  6. sqlmap-学习1 配置环境
  7. 视频教程-CCNA趣味实战无线实验视频课程—含PPPOE、ADSL、CABLE等-思科认证
  8. R语言——R和RStudio软件下载及安装
  9. 【专升本计算机】计算机文化基础练习题(选择题300道附答案)
  10. 学习计算机组装与维护的意义,计算机组装与维护课程学习体会
  11. 计算机组装实践第一课,计算机组装实践研究 毕业论文.doc
  12. 童年计算机课企鹅游戏,这些童年游戏,你一定玩过
  13. 构造者模式与Lombok的邂逅
  14. 对称加密和非对称加密!
  15. 字符串处理:输入字符串s1和s2以及插入位置f,在字符串s1中的指定位置f处插入字符串s2。如输入BEIJING, 123, 3,则输出:BEI123JING。
  16. 哈尔滨工业大学软件构造课程笔记第三章第四节
  17. A Game of Thrones(45)
  18. BERT: 理解上下文的语言模型
  19. 单向散列函数概述并基于MD5算法对文件哈希值实时监测
  20. 炸!1024我的故事,一个写了两年博客的大厂码农!

热门文章

  1. 医疗门诊ERP系统源码
  2. Cocos2d-x + Android + Eclipse + Windows 7
  3. python 界面一
  4. visio2016激活 试用版
  5. ironpython教程_用IronPython写winform程序-.NET教程,Asp.Net开发
  6. 突发:陆奇出任拼多多技术顾问委员会负责人
  7. 港科夜闻|香港科大张明杰教授课题组报道相分离介导突触前膜活性区的组织方式...
  8. 用Python生成答题库,辅助完成XX在线平台视频学习的课后考试
  9. 使用OpenStreetMap,Hot export tool,OSMNX下载地图资源
  10. DEA入门必备软件推荐--DEARUN