一、网络与网络流

给一个有向图(V,E),在V中指定一点,称为源点(记为vs),和另一点,称为汇点(记为vt),其余的点叫做中间点。对于E中每条弧(vi,vj)都对应一个正整数c(vi,vj)>=0(或简写为cij),称为f的容量,则赋权有向图N=(V,E,c,vs,vt)称为一个网络。所谓网络上的流,是指定义在弧集E上的一个函数f=f{f{vi,vj}},并称f(vi,vj)为弧(vi,vj)上的流量(下面简记为fij)。因此弧上有两个数,第一个表示容量cij,第二个表示流量fij。

二、可行流与最大流

在运输网络的实际问题中,我们可以看出,对于流有两个显然的要求:一是每个弧上的流量不能超过该弧的容量;二是中间点的流量为0,源点的净流出量和汇点的净流入量必相等且为这个方案的总输送量。因此有:

(1)容量约束:0≤fij≤cij,(vi,vj)∈E,
(2)守恒条件
对于中间点:流入量=流出量;对于源点与汇点:源点的净流出量vs(f)=汇点的净流入量(-vt(f))的流f,称为网络N上的可行流,并将源点s的净流量称为流f的流值v(f)
网络N中流值最大的流f*称为N的最大流。 

三、可增广路径

所为可增广路径,是指这条路径上的流可以修改,通过修改,使得整个网络的流值增大。

设f是一个可行流,P是从源点s到汇点t的一条路径,若P满足下列条件:

(1)在p上的所有前向弧(vi→vj)都是非饱和弧,即0≤fij<cij
(2)在p上的所有后向弧(vi←vj)都是非零弧,即0<fij≤cij
则称p为(关于可行流f的)一条可增广路径

四、最大流定理

当且仅当不存在关于f*的增广路径,可行流f*为最大流。

五、最大流算法

算法思想:最大流问题实际上是求一可行流{fij},使得v(f达到最大。若给了一个可行流f,只要判断N中有无关于f的增广路径,如果有增广路径,改进f, 得到一个流量增大的新的可行流;如果没有增广路径,则得到最大流。

1.寻求最大流的标号法(Ford,Fulkerson)
 从一个可行流(一般取零流)开始,不断进行以下的标号过程与调整过程,直到找不到关于f的可增广路径为止。
    (1)标号过程
    在这个过程中,网络中的点分为已标号点和未标号点,已标号点又分为已检查和未检查两种。每个标号点的标号信息表示两个部分:第一标号表明它的标号从哪一点得到的,以便从vt开始反向追踪找出也增广路径;第二标号是为了表示该顶点是否已检查过。
    标号开始时,给vs标上(s,0),这时vs是标号但末检查的点,其余都是未标号的点,记为(0,0)。
    取一个标号而未检查的点vi,对于一切未标号的点vj
    A.对于弧(vi,vj),若fij<cij,则给vj标号(vi,0),这时,vj点成为标号而未检查的点。
    B.对于弧(vi,vj),若fji>0,则给vj标号(-vi,0),这时,vj点成为标号而未检查的点。
    于是vi成为标号且已检查的点,将它的第二个标号记为1。重复上述步骤,一旦vt被标上号,表明得到一条从vi到vt的增广路径p,转入调整过程
    若所有标号都已检查过去,而标号过程进行不下去时,则算法结束,这时的可行流就是最大流。

  (2)调整过程
    从vt点开始,通过每个点的第一个标号,反向追踪,可找出增广路径P。例如设vt的第一标号为vk(或-vk),则弧(vk,vt)(或 相应地(vt,vk))是p上弧。接下来检查vk的第一标号,若为vi(或-vi),则找到(vi,vk)(或相应地(vk,vi))。再检查vi的第一 标号,依此类推,直到vs为止。这时整个增广路径就找到了。在上述找增广路径的同时计算Q:
          Q=min{min(cij-fij),minf*ij}
    对流f进行如下的修改:
    f'ij =  fij+Q   (vi,vj)∈ P的前向弧的集合
    f'ij =  fij-Q   (vi,vj)∈ P的后向弧的集合
    f'ij =  f*ij     (vi,vj)不属于P的集合
接着,清除所有标号,对新的可行流f’,重新进入标号过程。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

下面说一下EK算法

1、首先,什么是最大流

最大流就是从源点到经过的所有路径的最终到达汇点的所有流量和

2、EK算法的核心是反复寻找源点S到汇点t之间的增广路径,若有,找出增广路径上每一段[容量-流量]的最小值delta,若无,则结束。在寻找增广路径时,可以用BFS来找,并且更新残留网络的值(涉及到反向边)。

而找到delta后,则使最大流加上delta,更新为当前的最大流值。

这么一个图,求源点1,到汇点4的最大流

*** capacity存边的流量 ,进行ek求解

对于BFS找增广路:

1、flow[1]=INF,pre[1]=0;

源点1进队列,开始找增广路:

capacity[1][2]=40>0,则flow[2]=min(flow[1],40)=40;

capacity[1][4]=20>0,则flow[4]=min(flow[1],20)=20;

capacity[2][3]=30,则flow[3]=min(flow[2]=40,30)=30;

capacity[2][4]=20,但是pre[4]=1(已经在capacity[1][4]这遍历过4号点了)

capacity[3][4]......

当index=4(汇点),结束增广路的寻找

传递回increasement(该路径的流),利用pre前驱寻找路径

图也被改成

接下来同理

这就是最终完成的图,最终sumflow=20+20+10=50(这个就是最大流的值)

PS,为什么要有反向边呢?

我们第一次找到了1-2-3-4这条增广路,这条路上的delta值显然是1。于是我们修改后得到了下面这个流。(图中的数字是容量)

这时候(1,2)和(3,4)边上的流量都等于容量了,我们再也找不到其他的增广路了,当前的流量是1。

但这个答案明显不是最大流,因为我们可以同时走1-2-4和1-3-4,这样可以得到流量为2的流。

那么我们刚刚的算法问题在哪里呢?问题就在于我们没有给程序一个”后悔”的机会,应该有一个不走(2-3-4)而改走(2-4)的机制。那么如何解决这个问题呢?回溯搜索吗?那么我们的效率就上升到指数级了。

而这个算法神奇的利用了一个叫做反向边的概念来解决这个问题。即每条边(I,j)都有一条反向边(j,i),反向边也同样有它的容量。

我们直接来看它是如何解决的:

在第一次找到增广路之后,在把路上每一段的容量减少delta的同时,也把每一段上的反方向的容量增加delta。即在Dec(c[x,y],delta)的同时,inc(c[y,x],delta)

我们来看刚才的例子,在找到1-2-3-4这条增广路之后,把容量修改成如下

这时再找增广路的时候,就会找到1-3-2-4这条可增广量,即delta值为1的可增广路。将这条路增广之后,得到了最大流2。

那么,这么做为什么会是对的呢?我来通俗的解释一下吧。

事实上,当我们第二次的增广路走3-2这条反向边的时候,就相当于把2-3这条正向边已经是用了的流量给”退”了回去,不走2-3这条路,而改走从2点出发的其他的路也就是2-4。(有人问如果这里没有2-4怎么办,这时假如没有2-4这条路的话,最终这条增广路也不会存在,因为他根本不能走到汇点)同时本来在3-4上的流量由1-3-4这条路来”接管”。而最终2-3这条路正向流量1,反向流量1,等于没有流量。

这就是这个算法的精华部分,利用反向边,使程序有了一个后悔和改正的机会。而这个算法和我刚才给出的代码相比只多了一句话而已。

至此,最大流Edmond-Karp算法介绍完毕。

六、EK算法模板

#include<bits/stdc++.h>
using namespace std;
#define arraysize 201
int maxData=0x7fffffff;
int capacity[arraysize][arraysize];//记录残留网络的容量
int flow[arraysize];//标记从源点到当前节点实际还剩多少流量可用
int pre[arraysize];//标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中
int n,m;
queue<int>myqueue;
int BFS(int src,int des)
{int i,j;while(!myqueue.empty())//队列清空myqueue.pop();for(i=1;i<m+1;++i){pre[i]=-1;}pre[src]=0;flow[src]=maxData;myqueue.push(src);while(!myqueue.empty()){int index=myqueue.front();myqueue.pop();if(index==des)//找到了增广路径break;for(i=1;i<m+1;++i){if(i!=src&&capacity[index][i]>0&&pre[i]==-1){pre[i]=index;//记录前驱flow[i]=min(capacity[index][i],flow[index]);//关键:迭代的找增量myqueue.push(i);}}}if(pre[des]==-1)//残留途中不再存在增广路径return -1;elsereturn flow[des];
}
int maxFlow(int src,int des)
{int increasement= 0;int sumflow = 0;while((increasement=BFS(src,des))!=-1){int k = des;          //利用前驱寻找路径while(k!=src){int last = pre[k];capacity[last][k] -= increasement; //改变正向边的容量capacity[k][last] += increasement; //改变反向边的容量k = last;}sumflow += increasement;}return sumflow;
}
int main()
{int i,j;int start,end,ci;while(cin>>n>>m)//边的个数和终点{memset(capacity,0,sizeof(capacity));memset(flow,0,sizeof(flow));for(i=0;i<n;++i){cin>>start>>end>>ci;if(start == end)               //考虑起点终点相同的情况continue;capacity[start][end] +=ci;     //此处注意可能出现多条同一起点终点的情况}cout<<maxFlow(1,m)<<endl;}return 0;
}

最大流 EK算法

EK算法(网络流,最大流)相关推荐

  1. POJ 1966 Cable TV Network【无向图点连通度 最小割 E-K算法求最大流】

    题目描述: 给你一个无向图,问你最少删掉几个点,使这个图成不连通. 解题报告: 概念 (1)一个具有 N 个顶点的图,在去掉任意 k-1 个顶点后 (1<=K<=N) 所得的子图仍连通, ...

  2. EK算法网络流模板hdu1532

    hdoj 1532是一道可以作为模板题目练手. 模板代码: [cpp] view plaincopy print? #include <cstdio> #include <cstri ...

  3. (通俗易懂小白入门)网络流最大流——EK算法

    网络流 网络流是模仿水流解决生活中类似问题的一种方法策略,来看这么一个问题,有一个自来水厂S,它要向目标T提供水量,从S出发有不确定数量和方向的水管,它可能直接到达T或者经过更多的节点的中转,目前确定 ...

  4. 网络流之最大流算法——EK算法(通俗讲解)

    先放道模板题来说明网络流: Power Network A power network consists of nodes (power stations, consumers and dispatc ...

  5. 网络流——最大流EK算法讲解

    网络流--最大流EK算法讲解 好了,这是第二篇博客了,如第一篇所述,来讲一讲刚刚理解的网络流.因为本人只会EK算法,所以先讲这个算法.(我会去补知识点的!!!) 什么是网络流??? 读者们刚接触这个知 ...

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

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

  7. 网络流最大流----EK算法

    先来介绍一些基本概念: 网络是指一个有向图G=(V,E),有两个特殊节点:源点S和汇点T.每条有向边(x,y)都有一个权值c(x,y),称为边的容量.如果(x,y)不在图中,那么就有c(x,y)=0. ...

  8. 图论 —— 网络流 —— 最大流 —— Dinic 算法

    [概述] Dinic 算法在 EK 算法的基础上进行了优化,其时间复杂度为 O(n*n*m). Dinic 在找增广路的时也是找最短增广路, 但与 EK 算法不同的是 Dinic 算法并不是每次 bf ...

  9. 网络流问题以及EK算法复杂度分析

    网络流问题以及EK算法复杂度分析 一.网络流算法 通过一个例子引入网络流问题. 现有一个自来水厂要往家里通水,自来水厂用Vs表示,家用Vt表示.从自来水厂到家之间连接了很多水管,并且中途经过很多转接点 ...

  10. HDU 3549 Flow Problem(最大流模版EK算法)

    题目链接 第一道最大流,赤裸裸的模版题,刚好可以熟悉模版用.今天看了一下最大流,就看了一个EK算法,感觉有点和二分图匹配算法有点相似,对于最大流问题有点了解了,不过为什么这么做,也不是 很懂,只是把代 ...

最新文章

  1. grep 在HP-UX下的递归查找
  2. c++ 学习笔记 c++ 引用C库注意点:#ifdef __cplusplus 倒底是什么意思?
  3. hdu 1753大小数相加
  4. PHP Fatal error: Class #39;DOMDocument#39; not found
  5. 面试必问:常用的加密算法有哪些?
  6. springboot2.5.0 整合 redis 配置详解
  7. php7 imagick安装,php扩展imagick安装for windows7
  8. 记一次phpstudy重启后Apache无法启动
  9. 有两个关于内部类(Inner Class)的示例
  10. 使用C# impersonation进行windows帐号的校验
  11. java怎么安装_Java怎么安装?Java运行环境安装教程
  12. mybatis update 返回值
  13. ubuntu16.04配置opencv2、python2、cuda8.0、cudnn以及caffe
  14. 【软考】面向对象程序设计复习指南
  15. Mac硬盘格式转化好帮手——Tuxera NTFS
  16. 计算机汉字区位码十进制,[计 算 机]汉字区位码\国标码\机内码之间的换算
  17. 金网seo工具资源全套软件
  18. python中判断小写字符_Python islower()函数 判断字符串中字符是否都为小写
  19. html 中各种鼠标手势
  20. 大学生常用的pt网站

热门文章

  1. 【高德地图】获取我的位置信息
  2. 单区域——OSPF 讲解+配置命令(为了做双机热备实验)
  3. 金蝶生成凭证模板_凭证模板
  4. 医疗保险前台系统ER图1
  5. Word VBA:MathType公式与Latex公式切换
  6. 打印机显示smtp服务器未设置,打印机smtp服务器设置方法
  7. java高级学习视频下载
  8. DDC 显示器数据通道
  9. Contacts Provider基础
  10. C语言指针函数和函数指针区别