ISAP网络流算法

  ISAP全称Improved Shortest Augmenting Path,意指在SAP算法进行优化。SAP即Edmonds-Karp算法,其具体思路是通过不断向残存网络推送流量来计算整个网络的最大流。阅读本文要求掌握网络流的基础概念,不懂的出门左拐算法导论。ISAP的时间复杂度与EK算法一致,而EK算法的时间复杂度为min(O(E|f|),O(VE^2)),其中O(E|f|)部分是因为其是在FORD-FULKERSON算法上的改进。EK算法在FF算法的基础上将随意取增广路径替换为取最短增广路径,而ISAP在EK算法的基础上剔除了除了第一次外的后续广度优先搜索寻找最短路径的部分。下面对ISAP算法进行说明。

  先说明一些名词,称残存网络中容量非0的边为有效边。

  我们首先在EK算法的基础上,为每个顶点添加新的属性d,表示其到汇点t的最短路径(路径只能包含有效边),这个最短路径是基于残存网络的,而非原图,因此d属性会随着流的推送导致残存网络的变更而变更。显然要维护这样一个属性d,每次在推送流后,都需要基于新形成的残存网络重新执行广度优先搜索算法,以计算每个顶点正确的d属性,这样不就与EK算法完全一样了吗?是的,因此为了避免每次流推送都必须重新计算最短路径,我们需要修改d的定义,d表示顶点到t的距离的某个下界。为了说明这样定义之后就不用再每次重新执行广度优先搜索算法计算d,只需要说明每次向残存网络推送流,只会导致每个顶点到t的距离非严格递增:

  证明:假设我们向图G沿最短路径推送流,并形成新图G‘。我们记R(a,b)表示原图中从点a到点b的最短距离,记R‘(a,b)表示在新图(残存网络)中a到b的最短距离。我们所要证明的就是对于任意点x都有R(x,t)<=R‘(x,t)。假设存在点x,满足R(x,t)>R‘(x,t),显然x到t的最短路径之中必然包含由于流推送而新增的边,假设(v,u)是图G‘中x到t中距离点x最近的新增边,而(u,v)是处于G中最短增广路径上。这样我们就可以把G‘中的x到t的最短路径写作x,...,v,u,...,t,显然R‘(x,v)=R(x,v),因为其中不含新增边和删除边(即与G上的最短增广路径无交集)。由于R‘(x,t)<R(x,t)可得R‘(v,t)<R(v,t),从而有R‘(u,t)<R(u,t),因此由前面的说明可知存在增广路径的边(q,w),使得(w,q)存在于R‘(u,t)代表的最短路径中。利用同样的思路证明下去我们可以得到无穷多的增广路径上的边出现在了R‘(x,t)对应的路径之中,而由于一条最短路径是不可能包含重复边,且所有不同边的总数最多只有2*|E|条(正向边以及逆向边),因此这与R‘(x,t)是最短路径这一性质相悖,故假设不成立,因此R‘(x,t)>=R(x,t)。

  继续说明流程的执行。由于d是描述一个顶点距离t的下界,因此当一个顶点的属性d超过|V|时,这个顶点将永远无法推送流到t(最短路径不含相同顶点的简单应用)。而我们可以以源点s的属性d是否超过|V|来作为结束推送的条件。具体流程是我们循环推送,每次都从s开始向其余所有与s相邻且d属性为s.d-1的顶点推送无穷的流。我们期望这样的流推送成功当且仅当增广路径上的顶点序列的d属性为s.d,s.d-1,...,1,0,否则推送就不应该成功。显然在推送成功的情况下,由于d是距离下界,因此推送路径一定是最短的增广路径。而所谓的推送失败是指抵达一个顶点x(非t),所有邻接的可抵达顶点(指存在有效边连接)的距离都不等于x-1,这意味着附近的所有顶点到t的距离都由于前面对流的推送而增大了,因此我们也应该对x的距离进行增大(因为一个顶点距离t的最短距离应该是其与可以通过有效边连接的所有顶点到t的最短距离的最小值+1),由于周边的所有顶点的d属性均>=x.d,因此我们将x.d赋值为x.d+1也是合适的,不会违背我们对d的定义,在我们修改了d的值之后,显然这与我们期望的可推送的增广路径已经不相符了,因为d属性为x.d+1的顶点出现了两次,因此我们宣告失败回到之前的顶点。而当我们推送成功且x是方才推送的增广路径上的某个顶点,且此时从前面顶点传来的流还足够支持下次推送,那么我们可以继续寻找其满足d属性为x.d-1的后继顶点,继续推送(这也是ISAP的优化之一)。

  先说明程序会正确停止。由于推送成功就意味着存在增广路径(而且是符合严苛条件的最短增广路径),此时显然还可以继续通过向增广路径推送流来获得最大流。当我们发现不存在增广路径时,即s向周边推送失败,我们会不断增大s.d属性,而当s.d>|V|时,我们就结束推送,此时程序正确结束。

  时间复杂度与EK基本一致,只是将其中原本每次成功推送后执行广度优先搜索去掉,取而代之的是增加了推送失败情况下对顶点d属性的增大。由于一个顶点d属性不会超过|V|,因此我们可以保证每个顶点d属性最多增大|V|次,而总共有|V|个顶点,因此失败处理次数不会超过|V|^2。同时由于我们每次推送成功时也会遍历大量的不同边和不同顶点,这个流程在最糟糕的情况下的时间复杂度为O(|V|+|E|),与广度优先搜索算法一致,因此算法上界应该为O(VE^2+V^2)=O(VE^2),与EK算法一致。

  ISAP有一个通用的GAP优化就是我们将拥有不同d属性值的顶点进行分组,以d属性值作为编号。当我们修正一个顶点p的d属性值(推送失败时),我们可以通过判断p.d这一组元素是否只有一个,当只有一个时,意味着我们再修改p.d为p.d+1后,p.d这一组将会为空,这是一个好消息,因为后面所有从s发出的推送请求都会由于没有p.d组的顶点可以接受请求而失败,因此我们可以断定此时残存网络中的流即是最大流,我们可以通过提前将s.d修改为|V|来跳过后面一系列的失败处理,从而优化性能。

  下面给出代码:

  

bfs(t) //从t开始进行广度优先搜索,如果顶点v到t无路径,则v.d=-1  for v in V    v.d=-1   
    t.d = 0
    que = empty-queue
    que.enque(t)
    while(!que.isEmpty())
        head = que.deque()
        group[head.d]+=1
        for edge in head.edgeList
            if(edge.isNegative)//只允许沿着有效边的反向边移动
                if(edge.dst.d == -1)
                    edge.dst.d = head.d + 1
                    que.enque(edge.dst)

sendFlow(node, flowLimit) //通过顶点node向周围最多推送flowLimit单位的流,如果推送量为0,则表示推送失败
    total = 0
    for edge in node.edgeList
        if(edge.capacity > edge.flow && edge.dst.d == node.d - 1) //发现符合条件的有效边
            actually = sendFlow(edge.dst, min(flowLimit, edge.capacity - edge.flow)
            flowLimit -= actually
            total += actually       if(flowLimit == 0)         break
    if(total == 0) //如果发送失败
        group[node.d]-=1
        if(group[node.d] == 0) //发现断层
            s.d = |V|
        node.d+=1
        group[node.d]+=1
    return total

isap(s, t)
    bfs(t)
    if(s.d == -1)//如果从s到t不存在路径
        return 0
    sum = 0
    while(s.d < |V|)
        sum += sendFlow(s, INF)   return sum
时间: 2024-08-06 15:54:18

ISAP网络流算法的相关文章

网络流算法Dinic的Python实现

在上一篇我们提到了网络流算法Push-relabel,那是90年代提出的算法,算是比较新的,而现在要说的Dinic算法则是由以色列人Dinitz在冷战时期,即60-70年代提出的算法变种而来的,其算法复杂度为O(mn^2). Dinic算法主要思想也是基于FF算法的,改进的地方也是减少寻找增广路径的迭代次数.此处Dinitz大师引用了一个非常聪明的数据结构,Layer Network,分层网络,该结构是由BFS tree启发得到的,它跟BFS tree的区别在于,BFS tree只保存到每一层的

网络流算法--Ford-Fulkerson方法及其多种实现

原文链接:http://www.cnblogs.com/luweiseu/archive/2012/07/14/2591573.html 7. 网络流算法--Ford-Fulkerson方法及其多种实现 网络流 在上一章中我们讨论的主题是图中顶点之间的最短路径,例如公路地图上两地点之间的最短路径,所以我们将公路地图抽象为有向带权图.本章我们将对基于有向带权图的模型做进一步扩展. 很多系统中涉及流量问题,例如公路系统中车流量,网络中的数据信息流,供油管道的油流量等.我们可以将有向图进一步理解为"流

图论专题小结:网络流算法之ISAP算法

ISAP算法 ISAP(Improved Shortest Augument Path)算法是改进版的SAP算法,如果对效率要求很高的时候,可以用该算法. (1)概述:算法基于这样的一个事实:每次增广之后,任意结点到汇点(在残余网络中)的最短距离都不会减小.这样,我们可以利用d[i[表示结点i到汇点的距离的下界.然后再增广过程当中不断地修改这个下界.增广的时候和Dinic算法类似,只允许沿着d[i]==d[j]+1的弧(i,j)走. 不难证明,d[i[满足两个条件:(1)d[t]=0;(2)对任

网络流算法模板

通过USACO草地排水学习了一下网络流,终于写好了几个模板. 最大流 BFS求增广路径 简述:通过BFS在网络中找出一条最短增广路径并修改流量(前向弧加可改进量X,后向弧则减去X),当不存在增广路径时得出最大流,时间效率O(nm^2). { ID: qty1272 PROG: ditch LANG: PASCAL } program ditch; var c,f:array[0..200,0..200]of longint; path,u:array[0..200]of longint; n,i

[转] 网络流算法--Ford-Fulkerson方法及其多种实现

网络流 转载自:http://www.cnblogs.com/luweiseu/archive/2012/07/14/2591573.html 在上一章中我们讨论的主题是图中顶点之间的最短路径,例如公路地图上两地点之间的最短路径,所以我们将公路地图抽象为有向带权图.本章我们将对基于有向带权图的模型做进一步扩展. 很多系统中涉及流量问题,例如公路系统中车流量,网络中的数据信息流,供油管道的油流量等.我们可以将有向图进一步理解为“流网络”(flow network),并利用这样的抽象模型求解有关流量

网络流算法Push-relabel的Python实现

网络流的背景我就不多说了,就是在一个有向图中找出最大的流量,有意思的是,该问题的对偶问题为最小割,找到一种切分,使得图的两边的流通量最小,而且通常对偶问题是原问题的一个下界,但最小割正好等于最大流,即切割的边就是最大流中各个path饱和边的一个组合.说得可能比较含糊,这里想要了解清楚还是查阅相关资料吧. 最大流最原始最经典的解法就是FF算法,算法复杂度为O(mC),C为边的容量的总和,m为边数.而今天讲的Push-relabel算法是90年代提出的高效算法,复杂度为O(n^3),其实网络流最关键

关于网络流算法(2)

了解最大流解法: 网络流的相关基础知识很容易获得,详细的有<算导>,简单的有刘汝佳<算法竞赛入门>,这里选用的也是刘的书从Page207开始的内容. 这里要补充一些值得注意的基础: 最大流问题中的三个约束条件:容量限制条件.斜对成性条件.流量平衡条件: 网络流问题中边(Edge)的有向性. 1.1 BFS算法 因为<算法竞赛入门>中的E-K算法是基于BFS遍历方法的,说是很容易找到让DFS很慢的例子所以改为BFS,自己又已经把以前看的书全部忘记了,无奈只能开这个1.1,

HDU 3549 Flow Problem (用一道最裸的最大流开启网络流算法之路)

Flow Problem Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 9423    Accepted Submission(s): 4405 Problem Description Network flow is a well-known difficult problem for ACMers. Given a graph, y

关于网络流算法(3)

实现MCMF的基础上进行尝试针对题目修改代码就方便许多,这里的一个难点是如何输出MCMF对应的各条流路径(网络路径).实现了MCMF之后很长的一段时间我一直在走弯路,最后发现是自己的测试数据并不方便手算而且一开始采用的模板本身有错误,另一方面因为我之前并没有接触过图论算法,对这些现学的算法实现和运行细节不熟悉.在调整心态之后我决定使用自己设计的图作为调试用例并慢节奏地调试理解,稳扎稳打. 这里有一个博客,作者的思路与我一致,其内容对我有很大帮助. 2.1 多服务器(固定)-多消费结点.无输出的版