第26章:最大流

原创 2016年05月31日 14:43:59

一:流网络

流网络G=(V,E)是一个有向图,图中每条边(u,v)有一个非负的容量值c(u,v)0。而且如果边集合E包含一条边(u,v),则图中不存在反方向的边(v,u)。如果边(u,v)不属于E,则定义c(u,v)=0,并且图中不允许自循环。在流网络的所有结点中,我们特别分别出两个特殊结点,源结点s和汇点t,为方便起见,假定每个结点都在从源点到汇点的某条路径上。

我们现在可以给出流的形式化定义。假设G=(V,E)为一个流网络,其容量函数为c。假设s为源结点,t为汇点。图中任意边(u,v)的流是一个实值f(u,v),其满足下面两个性质

1:容量限制:对于所有的结点u和v,要求0f(u,v)c(u,v)

2:流量守恒:对于属于集合V-{s,t}的所有结点u来说,要求vVf(v,u)=vVf(u,v)。当(u,v)E时,从结点u到结点v之间没有流,因此f(u,v)=0;

我们称非负数值f(u,v)为从结点u到结点v的流。一个流f的值|f|定义如下:

|f|=vVf(s,v)vVf(v,s)

也就是说,流f的值是从源结点流出的总流量减去流入源结点的总流量。在最大流问题中,给定一个流网络G,一个源结点s和一个汇点t,我们希望找到值最大的一个流。

二:Ford-Fulkerson方法

Ford-Fulkerson方法循环增加流的值。在开始的时候,对于所有的结点u,vV, f(u,v)=0,给出的初始流值为0。在每一次迭代中,我们将图G的流值进行增加,方法就是在一个关联的“残存网络”Gf中寻找一条“增广路径”。一旦知道残存网络中一条增广路径的边,就可以很容易辨别出G中的一些具体的边,我们可以对这些边上的流量进行修改,从而增加流的值。虽然Ford-Fulkerson方法的每次迭代都增加流的值,但是对于图G的一条特定边来说,其流量可能增加,也可能减少;对某些边的流进行缩减可能是必要的,以便让算法可以将更多的流从源结点发送到汇点。重复对流进行这一过程,直到残存网络中不再存在增广路径为止,这时候会获得一个最大流。

在残存网络中寻找增广路径的方法有很多种,下面的代码是用广度优先搜索寻找增广路径。代码如下:

//求从源点source到汇点sink的最大流量
double ford_fulkerson_bfs(const vector<list<int>>& graph,const vector<vector<double>>& capacity,int source,int sink)
{
        vector<list<int>> residual_network=graph; //residual_network表示残余网络;
        vector<vector<double>> c=capacity; //c表示残余网络每条边对应的容量;
        double max_flow=0; //从源点source到汇点sink的最大流量;
        double flow=0;

        vector<int> pred=bfs(residual_network,source); //表示用广度优先搜索方法得到的残余网络中从源>结点s到汇点t的简单路径,也就是残余网络中增广路径;
        const int NIL=-1;  //NIL表示不存在的顶点;
        while(pred[sink]!=NIL){
                flow=residual_capacity(pred,c,sink); //返回增广路径中的残存容量;
                max_flow+=flow;

                int vertex=sink;
                while(pred[vertex]!=-1){
                        int last_vertex=pred[vertex];

                        if(flow<c[last_vertex][vertex])
                                c[last_vertex][vertex]-=flow;
                        else{
                                c[last_vertex][vertex]=0;
                                remove_edge(residual_network,last_vertex,vertex);
                        }

                        if(c[vertex][last_vertex]!=0){
                                c[vertex][last_vertex]+=flow;
                        }
                        else{
                                add_edge(residual_network,vertex,last_vertex);
                                c[vertex][last_vertex]=flow;
                        }

                        vertex=last_vertex;
                }

                pred=bfs(residual_network,source);
        }

        print_edge_flow_value(graph,c); //输出从源点到汇点的最大流值在图中每条边的分配;
        return max_flow;
}

//上述代码中的residual_capacity(),add_edge(),remove_edge(),print_edge_flow_value()代码如下:

//残余网络的一条增广路径能够为每条边增加的流量的最大值,也就是增广路径所有边中容量的最小值;
double residual_capacity(const vector<int>& pred,const vector<vector<double>>& capacity,int sink)
{
        double flow=DBL_MAX;

        int vertex=sink;
        const int NIL=-1; //NIL表示不存在的顶点;
        while(pred[vertex]!=NIL){
                int last_vertex=pred[vertex];

                if(capacity[last_vertex][vertex]<flow)
                        flow=capacity[last_vertex][vertex];

                vertex=last_vertex;
        }

        return flow;
}

void remove_edge(vector<list<int>>& graph,int u,int v)
{
        auto iter=find(graph[u].begin(),graph[u].end(),v);
        graph[u].erase(iter);
}

void add_edge(vector<list<int>>& graph,int u,int v)
{
        graph[u].push_back(v);
}

void print_edge_flow_value(const vector<list<int>>& graph,const vector<vector<double>>& residual_network_capacity)
{
        for(int u=0;u!=graph.size();++u)
                for(auto iter=graph[u].begin();iter!=graph[u].end();++iter)
                {
                        int v=*iter;

                        cout<<"edge( "<<u<<", "<<v<<") flow value: "<<residual_network_capacity[v][u]<<endl;
                }
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

算法导论 26章 最大流(一)

最大流问题 为了求一点到另一点的最短距离,我们可以把公路地图模型化为有向图。同理,我们可以将公路模型化为一个“流网络”(flow network),并运用它来解决物流相关的问题。其中...
  • zilingxiyue
  • zilingxiyue
  • 2015年03月22日 16:45
  • 2151

第26章 最大流(正在修改)

一、综述 1.定义 定义1:流网络 定义2:残留容量 定义3:增广路径 已知一个网络流G=(V,E)和流f,增广路径p为残留网络G|f中从s到t的一条简单路径 能够沿一条增广路径p...
  • mishifangxiangdefeng
  • mishifangxiangdefeng
  • 2013年05月18日 22:26
  • 5733

Windows核心编程 第26章 窗口消 息

窗 口 消 息     Wi n d o w s允许一个进程至多建立10 000个不同类型的用户对象(User object):图符、光标、窗口类、菜单、加速键表等等。当一个线程调用一个函数来建立某...
  • u013761036
  • u013761036
  • 2017年01月12日 00:44
  • 137

笨办法学python习题第26章答案

Exercise 26: Congratulations, Take a Test! import ex25 print "Let's practi...
  • Jane_yuhui
  • Jane_yuhui
  • 2017年01月19日 17:45
  • 418

《算法导论》笔记 第24章 总结与思考

【总结】 【思考】 24-1 dui
  • cyendra
  • cyendra
  • 2014年05月07日 20:00
  • 1113

lua程序设计第二版 读书笔记(5-8章)

书本下载地址                       http://download.csdn.net/detail/myy2012/5349646 本部分下载地址               ...
  • myy2012
  • myy2012
  • 2013年05月09日 17:04
  • 1206

《c++ primer》 第13章 拷贝控制 学习笔记

第 13 章 拷贝控制 1.拷贝,赋值与销毁 对初学c++的程序员来说,必须定义对象拷贝,移动,赋值或销毁时做什么。 拷贝构造函数:如果一个构造函数的参数是本身的引用,且其他的参数都有默认值,此...
  • wwh578867817
  • wwh578867817
  • 2014年12月15日 16:53
  • 2467

第26章读书笔记

26章code-tuning techniques读书心得书中列举了很多优化代码的实例,讲解的很清晰。我觉得没有必要把它再列举出来了,下面列出几点映像深刻的几点。1. 优化代码在不同语言之间效果不同U...
  • donkey2004112103
  • donkey2004112103
  • 2008年10月06日 17:34
  • 424

第26章 国际化

1、Java支持国际化的主要特征:          Java字符使用16位统一码编码;Java提供一个地区类Locale,封装有关地区特征的信息;Java利用类ResourceBundle将地区特...
  • hejiero
  • hejiero
  • 2014年01月21日 00:41
  • 532

JS DOM 编程艺术(第2版)读书笔记 第12章 综合示例

/** * addLoadEvent */ function addLoadEvent(func) { var oldonload = window.onload; if(type...
  • trr1994917
  • trr1994917
  • 2015年05月17日 10:37
  • 391
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:第26章:最大流
举报原因:
原因补充:

(最多只允许输入30个字)