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

一、网络流算法

通过一个例子引入网络流问题。
现有一个自来水厂要往家里通水,自来水厂用Vs表示,家用Vt表示。从自来水厂到家之间连接了很多水管,并且中途经过很多转接点。每根水管都有粗细,通过水管的水流量有个上界,超过则会撑爆水管。现在问:从自来水厂防水到家里,一共能够汇集多少水。这就是网络流的最大流问题。

网络流问题:从源点(Vs)到汇点(Vt)所经过的所有路径,最终到达汇点的所有流量之和。
网络流算法就是为了求解最大流问题。
对于一个流网络G = (V, E), 容量函数为c,源点为Vs,汇点为Vt,G的可行流f满足如下三个性质:

  • 容量限制:对所有的u,v∈V,要求f(u,v)<=c(u,v)。
  • 反对称性:对所有的u,v∈V,要求f(u,v)=-f(v,u)。
  • 流守恒性:对所有u∈V-{s,t},要求∑f(u,v)=0 (v∈V)。

二、增广路定理

定义每条边(u,v)有一个容量c(u,v),流量 f(u,v), 残量r(u,v) = c(u,v)-f(u,v).
r(u, v) 构成残留网络。在残量网络上寻找到一条可行流,称为增广路
当残留网络中没有增广路时,网络流达到最大流。
下面我们通过几张图来看一下找可行流的过程。
(1)首先这是一张网络流图。

(2)假设我们找到一条可行流 :1——2——3——4,流量为2,所以在这几条边上的容量变为0。

这个时候我们发现在图中再也找不到可行流了。也就是最大流为2。
但是如果我么选择的是1——2——4和1——3——4两条可行流,那么最大流应该是2+1=3,所以这个时候我们需要有办法重新分配流量的路线。
这就引入了网络流算法的精髓之处:增加反向边。
(3)增加反向边

(3)增加反向边之后,找到路径:1——3——2——4.流量为1,最大流为2+1=3.

关于为什么要增加反向边,很多博客里写的都是那句话,“给程序一个反悔的机会,把分错的流量撤销后进行重新分配。”
这样说其实不好理解。很多人可能会冒出和我一样的问题,就是为什么可以平白无故增加反向边,认为流量可以逆流。
我个人的理解是,流量不是逆流,我们是在找一种新的分配方式,就是流量如果有两个出口,我们可以对两个出口进行分配。如果我们把2的流量(2份)全部分配到3,不是最优解,所以我们就得尝试分1份分配到3,剩下一份继续分配,发现可以分配到4。所以汇集到4的流量,1份来源于2流出流量的再分配(1份到3再到4,另一份直接到4),还有一份来源于3。

三、Edmons-karp算法(EK算法)

  • 从源点开始,用BFS找一条最短的增广路径,计算该路径上的残量最小值,累加到最大流值;
  • 沿着该路径修改流量值,实际是修改是残量网络的边权;
  • 重复上述步骤,直到找不到增广路时,此时得到的流就是最大流。

我们用图来演示算法的运行过程:
initialize :

  • graph 存图;
  • pre:前驱数组,记录前驱点;
  • d:记录路径中最小流量;
  • visit:记录该点是否被访问;
  • flow:记录最大流量;
  • queue:bfs所用队列,找路径。

**step1:queue = [], pre[1] = -1, maxflow = 0

step2: 访问点1,加入队列,queue =[1], pre[1] = -1

step3: 1出队列,2,3入队,queue=[2,3], pre[2] = 1, pre[3] = 1

step4:2出队列,4入队列,queue=[3,4]. pre[4] = 2
得到路径:1–>2–>4


step5: 修改该路径上的边权,增加反向边, d(4,2) = 2, d(2,1) = 2, dmin = 2,maxflow = 2

**找到路径:1–>3–>4,dmin = 1, maxflow = 2+1 = 3

四、代码实现

#usr/bin/python3
#最大流-EK算法
def bfs(graph, s, t):global visitglobal pren = len(graph)visit = [False for i in range(n)] #记录是否访问pre = {}queue = []pre[s] = -1visit[s] = Trueprint('visit:', visit)queue.append(s)while queue:p = queue.pop(0)for i in range(len(graph[p])):#print('p:',p)if graph[p][i] > 0 and visit[i] == False:pre[i] = pvisit[i] = Trueprint(p, i)if i == t:print("找到一条增广路径")print("visit:", visit)return Truequeue.append(i)return Falsedef EdomonsKarp(graph, s, t):print('s:',s,'t:',t)global flowglobal dd = 0flow = 0while bfs(graph, s, t):d = graph[pre[t]][t]x = t while pre[x] != -1:print('点:', x, '前驱点:', pre[x])d = min(graph[pre[x]][x], d)print("从点",x,"到点",pre[x],'流量最小值为', d)x = pre[x]x = twhile pre[x] != -1:graph[pre[x]][x] -= dgraph[x][pre[x]] += d x = pre[x]print('graph:', graph)flow += dprint(flow)return flowif __name__ == "__main__":graph = [[0, 2, 2, 0],[0, 0, 2, 2],[0, 0, 0, 2],[0, 0, 0, 0]]n = len(graph)visit = [False for i in range(n)] #记录是否访问#pre = {} #记录前驱点s = 0t = 3flow = EdomonsKarp(graph, s, t)print(flow)

广度优先搜索:如果采用邻接矩阵作为图的存储结构,时间复杂度为O(V*2),如果采用邻接表作为图的存储结构,时间复杂度为O(V+E)
深度优先搜索:和上述一样
解释:广度优先搜索的时间复杂度分析,由于每个节点仅被发现一次,因此每个节点入栈和出栈各一次,时间复杂度均为O(1),故入栈和出栈的总时间为O(V),最坏的情况下,需要对每个节点的邻接点进行扫描,所以时间复杂度为O(E),在此之后,每条边至少访问一次,这是因为在搜索的过程中,若某个节点向下搜索时,其子节点都访问过了,这时候就会回退,所以时间复杂度为O(E),所以总的时间复杂度为O(V+E);
邻接矩阵存储方式时,查找每个顶点的邻接点所需时间为O(V),又有n个顶点,所以时间复杂度为O(V^2).

五、EK算法时间复杂度分析

引理:EK算法每次增广都会使得所有顶点v∈V−{s,t}v\in V - \{s,t\}v∈V−{s,t}到sss的最短距离d[v]d[v]d[v]增加。
采用反证法,假设存在一个点v∈V−{s,t}v\in V-\{s,t\}v∈V−{s,t},使得d′[v]<d[v]d'[v] < d[v]d′[v]<d[v]。v的前驱点为u。
因此可以得到
d[u]=d[v]−1,d′[u]>=d[u]d[u] = d[v]-1, d'[u] >= d[u]d[u]=d[v]−1,d′[u]>=d[u]
那么显然边(u,v)i̸nE(u,v)\not in E(u,v)​inE, 因为如果(u,v)∈E(u,v) \in E(u,v)∈E,则一定有
d[v]<=d[u]+1<=d′[u]+1=d′[v]d[v] <= d[u]+1 <= d'[u]+1 = d'[v]d[v]<=d[u]+1<=d′[u]+1=d′[v]
与假设矛盾。
所以EK算法一定是增加了流f(u,v)f(u,v)f(u,v),即边(v,u)(v,u)(v,u)在GGG的最短路上,固有,
d[v]=d[u]−1<=d′[u]−1=d′[v]−2d[v] = d[u] - 1 <= d'[u] - 1 = d'[v]-2d[v]=d[u]−1<=d′[u]−1=d′[v]−2
与假设矛盾所以引理成立。

定理:EK算法的最多增广次数为 O(VE)O(VE)O(VE)
若增广路ppp的残留容量等于边(u,v)(u,v)(u,v)的残留容量,则称边(u,v)(u,v)(u,v)是增广路ppp的关键边,下面用引理证明每条边最多做关键边∣v∣2−1\frac{|v|}{2}-12∣v∣​−1次。

对于关键边(u,v)(u,v)(u,v),由于(u,v)(u,v)(u,v)在最短路上,有
d[v]=d[u]+1d[v] = d[u] + 1d[v]=d[u]+1
而增广后,(u,v)(u,v)(u,v)将会从GGG中消失,重新出现的条件是(v,u)(v,u)(v,u)出现在增广路上。那么则有
d′[u]=d′[v]+1d'[u] = d'[v] + 1d′[u]=d′[v]+1
由引理我们知道
d′[v]>=d[v]d'[v] >= d[v]d′[v]>=d[v]
故有
d′[u]>=d[v]+1=d[u]+2d'[u] >= d[v] + 1 = d[u] + 2d′[u]>=d[v]+1=d[u]+2
所以每次出现至少会使得最短距离+2+2+2,而其距离最大为∣V∣−2|V|-2∣V∣−2,所以每条边最多做关键边∣V∣2−1\frac{|V|}{2}-12∣V∣​−1次,总的增广次数就为O(VE)O(VE)O(VE).

所以采用BFS进行增广的话, EK算法将达到复杂度O(VE2)O(VE^2)O(VE2)
但实际情况中,EK算法的复杂度远低于理论上的复杂度。

网络流问题以及EK算法复杂度分析相关推荐

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

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

  2. 算法复杂度分析(下)

    前一篇文章算法复杂度分析(上)讲述了复杂度的大 O 表示法和几个分析原则,这篇文章我们来讲讲另外几种复杂度,最好情况时间复杂度(best case time complexity).最坏情况时间复杂度 ...

  3. 八大排序:Java实现八大排序及算法复杂度分析

    目录 QUESTION:八大排序:Java实现八大排序及算法复杂度分析 ANSWER: 一:冒泡排序 1.算法分析 2.时间复杂度分析 3.代码 二:选择排序 1.算法分析 2.时间复杂度分析 3.代 ...

  4. 算法复杂度分析看这一篇就够了

    执行效率是算法一个非常重要的考量指标,而时间复杂度和空间复杂度则是衡量算法代码的执行效率. 为什么需要复杂度分析 通常情况下,我们可以在写完代码的情况下把程序跑一遍,通过统计.监控,就能得出算法执行的 ...

  5. 算法之如何进行算法复杂度分析

    一.什么是复杂度分析? 1.数据结构和算法解决是"如何让计算机更快时间.更省空间的解决问题". 2.因此需从执行时间和占用空间两个维度来评估数据结构和算法的性能. 3.分别用时间复 ...

  6. 怎么算matlab算法复杂度,算法复杂度分析

    1. 何为数据结构?何为算法? 简单来说,数据结构就是数据的存储方式,比如数组就是把数据存在一段连续的内存上,而链表则是通过指针的关联将数据存在任意可用的内存上:栈是先进后出,队列是先进先出. 而算法 ...

  7. 算法复杂度分析(下):最好、最坏、平均、均摊等时间复杂度概述

    细化时间复杂度分析 代码千千万,有些代码逻辑会很复杂,所以为了更细化的分析算法的复杂度,再复杂度分析方面引入了4个知识点: 1.最好情况时间复杂度(best case time complexity) ...

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

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

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

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

最新文章

  1. iOS 简简单单构造单例
  2. 【译】Tablix指南----通向报表服务的阶梯系列(四)
  3. [css] 说下line-height三种赋值方式有何区别?
  4. matlab的7.3版本是什么_乐建工程宝V6.3版本升级说明公告
  5. 关于ics lab8 performance中的smooth
  6. 以CSS方式提高您网站的速度
  7. Dangling Javadoc comment
  8. java程序猿总结出来的经验
  9. iOS开发-retain/assign/strong/weak/copy/mutablecopy/autorelease区别
  10. MYSQL 数据库创建,修改等知识整理
  11. 2022(2021JCR)SCI期刊影响因子完整版
  12. 规则引擎实现生产调度系统
  13. Json转换成excel 离线版
  14. unity物理引擎介绍
  15. AE duik插件运用-人物行走动画
  16. 【001】Zabbix学习笔记-Zabbix简介与部署
  17. 【Python • 图片识别】pytesseract快速识别提取图片中的文字
  18. 蚂蚁海图tms切片工具
  19. PTA 7-13 列车调度 (25 分) C语言和C++实现(二分查找)
  20. python图像锐化 增强边缘_[Python图像处理]十一.图像锐化与边缘检测之Roberts算子、Prewitt算子、Sobel算子和Laplacian算子,Schar算子...

热门文章

  1. 什么是Use Case?
  2. 车轮件缺陷分析及设计优化 | 智铸超云案例分享
  3. 仓储委外加工/周转加工
  4. 2021年信息产业十大技术趋势
  5. 网站首页被K的原因及其恢复方法
  6. 考研政治——马克思三大原理之对立统一
  7. 各种搞怪的标点符号表情
  8. java语言开发手机游戏_手机上的JAVA游戏和JAVA软件,是电脑上的JAVA语言编写的吗?他们之间有什么联系...
  9. 微型计算机配置清单办公,式电脑配置清单.doc
  10. kubernetes部署dashboard可视化插件