最大流算法(Edmons-Karp + Dinic 比较) + Ford-Fulkson 简要证明
#include <cstdio>
#include <cstring>
#define min(x,y) (x>y?y:x)
int pre[],q[];
int F[][];
int n,nc,np,m,s,t,all;
int MaxFlow(int s, int t){
int ans=;
while(){
memset(pre,,sizeof(pre));
int head=,tail=;
q[++tail]=s;
while(head<tail&&pre[t]==){
int cur=q[++head];
for(int i=; i<=n; i++)
if(F[cur][i]>&&pre[i]==){
pre[i]=cur;
q[++tail]=i;
}
}
if(pre[t]==) break;
int minF=;
for(int i=t; i!=s; i=pre[i])
minF=min(minF,F[pre[i]][i]);
for(int i=t; i!=s; i=pre[i])
{
F[pre[i]][i]-=minF;
F[i][pre[i]]+=minF;
}
ans+=minF;
}
return ans;
}
int main()
{
int x,y,z;
while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF){
all=;
memset(F,,sizeof(F));
s=n+;
t=n+;
n=n+;
for(int i=; i<m; i++){
while(getchar()!='(') ;
scanf("%d,%d)%d",&x,&y,&z);
F[x+][y+]=z;
}
for(int i=; i<np; i++){
while(getchar()!='(') ;
scanf("%d)%d",&x,&z);
F[s][x+]=z;
}
for(int i=; i<nc; i++){
while(getchar()!='(') ;
scanf("%d)%d",&x,&z);
F[x+][t]=z;
}
printf("%d\n",MaxFlow(s,t));
}
return ;
}
Dinic用DFS实现:360ms
#include <cstdio>
#include <cstring>
#define min(x,y) ((x)>(y)?(y):(x))
#define N 105
#define M 10005
int n,np,nc,m,all,s,t;
int d[N],be[N];
struct Edge{
int x,y,c,next;
}e[M*];
void add(int x, int y, int z)//需保证相反边第一个为偶数
{
e[all].x=x; e[all].y=y; e[all].c=z;
e[all].next=be[x];
be[x]=all;
all++;
e[all].x=y; e[all].y=x; e[all].c=;
e[all].next=be[y];
be[y]=all;
all++;
}
bool BFS(int s, int t)
{
memset(d,-,sizeof(d));
int head=,tail=,q[N];
q[++tail]=s;
d[s]=;
while(head<tail){
int cur=q[++head];
for(int i=be[cur]; i!=-; i=e[i].next)
if(e[i].c> && d[e[i].y]==-){
d[e[i].y]=d[cur]+;
q[++tail]=e[i].y;
}
}
return d[t]!=-;
}
int DFS(int cur, int minc)
{
if(cur==t) return minc;//表示路径上该点前方最小容量
int ans=,tmp;//ans表示该点要增大的流
for(int i=be[cur]; i!=-; i=e[i].next)
if(e[i].c> && d[e[i].y]==d[cur]+ && (tmp=DFS(e[i].y,min(minc-ans,e[i].c))))//多路增广很快 因为不用返回到s 容易证明能保证minc>0
{
e[i].c-=tmp;
e[i^].c+=tmp;
ans+=tmp;
}
if(ans==) d[cur]=-;//关键的一句话 否则超时 用于多路增广
return ans;
}
int Dinic(int s, int t)
{
int ans=,tmp;
while(BFS(s,t)){
while(tmp=DFS(s,))
ans+=tmp;
}
return ans;
}
int main()
{
int x,y,z;
while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF){
all=;
memset(be,-,sizeof(be));
s=n;
t=n+;
n=n+;
for(int i=; i<m; i++){
while(getchar()!='(') ;
scanf("%d,%d)%d",&x,&y,&z);
add(x,y,z);
}
for(int i=; i<np; i++){
while(getchar()!='(') ;
scanf("%d)%d",&x,&z);
add(s,x,z);
}
for(int i=; i<nc; i++){
while(getchar()!='(') ;
scanf("%d)%d",&x,&z);
add(x,t,z);
}
printf("%d\n",Dinic(s,t));
}
return ;
}
Dinic用栈模拟递归实现:63ms
#include <cstdio>
#include <cstring>
#define min(x,y) ((x)>(y)?(y):(x))
#define N 105
#define M 10005
int n,np,nc,m,all,s,t;
int d[N],be[N];
struct Edge{
int x,y,c,next;
}e[M*];
void add(int x, int y, int z)//需保证相反边第一个为偶数
{
e[all].x=x; e[all].y=y; e[all].c=z;
e[all].next=be[x];
be[x]=all;
all++;
e[all].x=y; e[all].y=x; e[all].c=;
e[all].next=be[y];
be[y]=all;
all++;
}
bool BFS(int s, int t)
{
memset(d,-,sizeof(d));
int head=,tail=,q[N];
q[++tail]=s;
d[s]=;
while(head<tail){
int cur=q[++head];
for(int i=be[cur]; i!=-; i=e[i].next)
if(e[i].c> && d[e[i].y]==-){
d[e[i].y]=d[cur]+;
q[++tail]=e[i].y;
}
}
return d[t]!=-;
}
int Dinic(int s, int t)//防止爆栈 用stack模拟递归
{
int ans=;
int stack[N],top;
int begin[N];
while(BFS(s,t))
{
memcpy(begin,be,sizeof(be));
int cur=s;
top=;//dfs开始 清空栈
while()
{
if(cur==t){
int minc=,mini;
for(int i=; i<top; i++)
if(minc>e[stack[i]].c)
{
minc=e[stack[i]].c;
mini=i;//以便之后回到这继续增广
}
for(int i=; i<top; i++)
{
e[stack[i]].c-=minc;
e[stack[i]^].c+=minc;//第一个二进制取反 即取相反边
}
ans+=minc;
top=mini;
cur=e[stack[mini]].x;
}
for(int i=begin[cur]; i!=-; begin[cur]=i=e[begin[cur]].next)
if(e[i].c> && d[e[i].y]==d[e[i].x]+) break;
if(begin[cur]!=-){
stack[top++]=begin[cur];
cur=e[begin[cur]].y;
}else{
if(top==) break;
d[cur]=-;//当前节点不在增广路中 删除
cur=e[stack[--top]].x;//回溯
}
}
}
return ans;
}
int main()
{
int x,y,z;
while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF){
all=;
memset(be,-,sizeof(be));
s=n;
t=n+;
n=n+;
for(int i=; i<m; i++){
while(getchar()!='(') ;
scanf("%d,%d)%d",&x,&y,&z);
add(x,y,z);
}
for(int i=; i<np; i++){
while(getchar()!='(') ;
scanf("%d)%d",&x,&z);
add(s,x,z);
}
for(int i=; i<nc; i++){
while(getchar()!='(') ;
scanf("%d)%d",&x,&z);
add(x,t,z);
}
printf("%d\n",Dinic(s,t));
}
return ;
}
之前一题poj1459是经典最大流题目,倒是想要回顾一下,顺便将书中证明简要摘出:(哈哈)
而网络流的增广路与二分图还是有相当的差别的,那么如何来判断网络流的流量最大呢,那么得清楚如何使得当前网络流的流量再次增大,首先显而易见的就是直接用bfs找出前进路径中所能增加的最大流量,这个是毋庸置疑的.只有这种情况吗?我们只考虑了前向边,而后向边得想想是否能够增加的余地.
先看看这个图 (时间不够先粗略画这)
仔细看s-1-2-t,是否能增加,用s-1的流量顶替2-1的流量后2-t的流量自然增加,
故我们只需不断的找出这两种增广路径,然后更新即可.
因此:
(前向边:路径上边方向是从s指向t的边;后向边:路径上边方向从t指向s的边)
对于路径上所有前向边(u,v)满足f(u,v)<c(u,v)且所有后向边(v,u)满足f(v,u)>0,则该路径称为增广路径.
证明:只要当前网络中不存在从s到t的增广路径,则当前流为最大流.
要证明这个定理,我们得先引入最大流最小割定理.
割的概念:对于网络流图D=(V,E,C)的所有节点集,将该节点集分为集合S和T,且其中源点s∈集合S,汇点t属于T,对于图上满足u∈S,v∈T的所有边(u,v)的集合称为割,其中割中每条边的容量和称为割的容量.而容量最小的割称为最小割.
最大流最小割定理即:在一个给定的网络流图上,最大流等于最小割的容量.
证明:
设网络流图D的网络流f使得流量达到最大.
定义割(S,T):
1.源点s∈S
2.若u∈S,且f(u,v)<c(u,v),则v∈S
3.若u∈S,且f(v,u)>0,则u∈S
显然,源点t∈T,否则若t∈S,则由割的定义,必然从s到t中存在一条增广路径,则与f为最大流矛盾,因此t∈T.故从s到t间的所有路径必然都需要从S到T即需要经过割中的边,又由割(S,T)的定义,f(u,v)=c(u,v),c(v,u)=0因此sigama(f)=sigama(c(u,v)-c(v,u))=sigama(c(u,v))(其中u∈S,v∈T),即最大流的总流量等于割(S,T)的边容量,现在只需证明割(S,T)为最小割.
假设割(S,T)不为最小割,则f就不是最大流,因为总流量必然小于最小割的容量,因为从s到t的所有路径必然需要经过从S到T的过程,故总流量必然小于任意S与T的割的容量,即小于最小割的容量,故f非最大流,矛盾,故割(S,T)为最小割
得证.
而在最大流的情况下,最小割(即上述割(S,T))的定义,即无增广路径.
因此只要当前网络中不存在从s到t的增广路径,则当前流为最大流.
而至于流程我们只需重复进行:
1.找增广路径,找出最大可增量a=min(前向边c(u,v)-f(u,v),后向边f(v,u))
2.修改增广路径上每条前向边f(u,v)+a;后向边f(v,u)-a;
原来Ford-Fulkerson即上面1~2的思想,是用来求最大流的“方法”,若朴素查找增广路即一次增加1流量,复杂度为O(N*F)
而通过广搜来实现查找增广路径的“算法”是Edmonds-Karp算法O(N*M^2)
而Dinic算法,每次更新层次图广搜一遍O(M),而进行增广时每增广一次删除一个点,最多删除n个点,因此为O(N^2),因此总复杂度为O(N^2*M)
最大流算法(Edmons-Karp + Dinic 比较) + Ford-Fulkson 简要证明的更多相关文章
- 最大流算法之Dinic
		
引言: 在最大流(一)中我们讨论了关于EK算法的原理与代码实现,此文将讨论与EK算法同级别复杂度(O(N^2M))的算法--Dinic算法. Dinic算法用到的思想是图的分层结构,通过BFS将每一个 ...
 - 图论算法-最小费用最大流模板【EK;Dinic】
		
图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...
 - Ford-Fulkerson 最大流算法
		
流网络(Flow Networks)指的是一个有向图 G = (V, E),其中每条边 (u, v) ∈ E 均有一非负容量 c(u, v) ≥ 0.如果 (u, v) ∉ E 则可以规定 c(u, ...
 - 最大流算法之ISAP
		
序: 在之前的博文中,我解释了关于最大流的EK与Dinic算法,以及它们的STL/非STL的实现(其实没什么区别).本次讲解的是ISAP算法.'I',指 inproved,也就是说ISAP其实是SAP ...
 - 最大流算法-ISAP
		
引入 最大流算法分为两类,一种是增广路算法,一种是预留推进算法.增广路算法包括时间复杂度\(O(nm^2)\)的EK算法,上界为\(O(n^2m)\)的Dinic算法,以及一些其他的算法.EK算法直接 ...
 - 算法9-5:最大流算法的Java代码
		
残留网络 在介绍最大流算法之前先介绍一下什么是残留网络.残余网络的概念有点类似于集合中的补集概念. 下图是残余网络的样例. 上面的网络是原始网络.以下的网络是计算出的残留网络.残留网络的作用就是用来描 ...
 - 海量数据挖掘MMDS week3:流算法Stream Algorithms
		
http://blog.csdn.net/pipisorry/article/details/49183379 海量数据挖掘Mining Massive Datasets(MMDs) -Jure Le ...
 - 基于.net的分布式系统限流组件(限流算法:令牌算法和漏斗算法)
		
转载链接:https://www.cnblogs.com/vveiliang/p/9049393.html 1.令牌桶算法 令牌桶算法是比较常见的限流算法之一,大概描述如下: 1).所有的请求在处理之 ...
 - 网络最大流算法—EK算法
		
前言 EK算法是求网络最大流的最基础的算法,也是比较好理解的一种算法,利用它可以解决绝大多数最大流问题. 但是受到时间复杂度的限制,这种算法常常有TLE的风险 思想 还记得我们在介绍最大流的时候提到的 ...
 - poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分, dinic, isap
		
poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分 dinic /* * Author: yew1eb * Created Time: 2014年10月31日 星期五 ...
 
随机推荐
- javascript之流程控制 和函数的容易忽略点
			
1.流程控制 1> for in 仅用于 对象的遍历: var box={ "name":'小红', 'age':18, 'height':165 }; for(var b ...
 - MyEclipse 2013官网下载地址以及破解方法
			
刚刚发布了MyEclipse 2013,我现在用的还是6.5的版本,6.5的版本是我觉得最好用的一个版本. 我装上了,还没感受到有哪些好用,就是感觉体积庞大,和IBM 的WID一样,是个多面手,啥事都 ...
 - android编程常见问题-No Launcher activity found!
			
新手编程常见的问题: 问题表现: console提示:No Launcher activity found! The launch will only sync the application pac ...
 - myeclipse trial expired[转]
			
转自:http://blog.csdn.net/yuyuyuyuy/article/details/5878122 今天MyEclipse提示过期了,MyEclipse Trial Expired. ...
 - 关于12306登陆页面dynamicJs的获取
			
今天帮与一个朋友探讨此事,刚开始一直是以为访问404,但是发现返回为200,没有问题,后来才知道朋友想了解的是为何浏览器可以获取到/otn/dynamicJs,但是自己手动获取就获取不到了 找了很久r ...
 - [转载]点评阿里云、盛大云等国内IaaS产业
			
免责声明: 本文转自网络文章,转载此文章仅为个人收藏,分享知识,如有侵权,请联系博主进行删除. 原文作者:刘黎明 原文地址:http://www.chinacloud.org ...
 - Maven--(一个坑)在settings.xml文件中添加mirrors导致无法新建Maven项目
			
这是用新电脑第一次创建Maven项目--当然是一个测试项目.已经差不多忘了该怎样做,所以参考我的博客:http://www.cnblogs.com/wql025/p/4996486.html,这应该是 ...
 - SQL语言笔记
			
字符串用单引号',判断用单等号=,两个单引号''转义为一个单引号' 不等号是<> 不区分大小写 []括起来的要不是关键字,要不是非法变量,比如空格隔起来的变量 创建与删除数据库 - ...
 - 项目中的Libevent(多线程)
			
多线程版Libevent //保存线程的结构体 struct LibeventThread { LibEvtServer* that; //用作传参 std::shared_ptr<std::t ...
 - (转)CentOS5.5 下搭建 PHP 环境(最佳的LAMP环境)
			
本文详细阐述在 Linux 系统中搭建 PHP 环境,由于 PHP 就是由 C 语言编写的,最初也是运行在 Linux 系统中,所以Linux 是 PHP 的最佳环境. 关于本文中使用到的软件,请点击 ...