关于网络流算法(2)

了解最大流解法:

网络流的相关基础知识很容易获得,详细的有《算导》,简单的有刘汝佳《算法竞赛入门》,这里选用的也是刘的书从Page207开始的内容。

这里要补充一些值得注意的基础:

  • 最大流问题中的三个约束条件:容量限制条件、斜对成性条件、流量平衡条件;
  • 网络流问题中边(Edge)的有向性。

1.1 BFS算法

因为《算法竞赛入门》中的E-K算法是基于BFS遍历方法的,说是很容易找到让DFS很慢的例子所以改为BFS,自己又已经把以前看的书全部忘记了,无奈只能开这个1.1,非常惭愧。

BFS,Broad First Search,广度优先搜索算法,或,层序遍历算法。算法的理解部分只需要记住一句话:依次访问已经访问过的顶点的未访问临接顶点。、

实现层面,由于对于节点的遍历是顺序的、FIFO的,所以使用队列辅助进行顺序控制。

用邻接矩阵实现的BFS算法代码如下:

 1 void bfs(int s, bool edge[][maxn])
 2 {
 3     visit(s,visited);
 4     q.push(s);
 5     while(!q.empty())
 6     {
 7         s = q.front();
 8         q.pop();
 9         for(int w = next_Neighbor(s,0,edge);w>=0;w=next_Neighbor(s,w,edge))
10         {
11             if(!visited[w])
12             {
13                 visit(w,visited);
14                 q.push(w);
15             }
16         }
17     }
18 }

1.2 Edmonds-Karp算法(增广路算法)

E-K算法是最基础的最大流算法,主要思想是从最小流状态迭代增加流量,直到不能继续增加达到稳态。

其中迭代的过程称为“增广”,即对于某个s到t的流量通路,如果其上各边流量都没有达到各自的容量(流量上限),那么就在这条通路上增加这些边中的最小残量单位的流量。

E-K算法涉及到一个反向更新流量的问题,需要在代码中自己体会。

这里我贴个随笔,觉得写得很接地气。这篇文章中关于反向边权值的表达是“退回”,这个在《算法竞赛入门》也有部分表述,可以结合在一起看,另外补充一个比较全面的教程

使用邻接矩阵实现的代码如下:

 1 /*
 2 不断寻找残量网络中汇点的可达路径,
 3 可达路径中的各条边每次迭代减少可达路径中所有边 capacity 最小值直到在残量网络中汇点不可达
 4 */
 5
 6 #include<iostream>
 7 #include<queue>
 8 using namespace std;
 9 const int arrsize = 10;
10 const int maxdata = INT_MAX;
11
12 int cap[arrsize][arrsize];        //表示两个结点之间的最大可用流量
13 int flow[arrsize],pre[arrsize];    //表示从原点到index结点的当前剩余可用流量
14 queue<int> q;
15
16
17 int BFS(int src, int des)
18 //BFS函数,寻找可行通路
19 {
20 //cout<<endl<<"进入BFS"<<endl;
21     while(!q.empty())
22         q.pop();
23
24     memset(pre,-1,sizeof(pre));
25
26     pre[src] = 0;
27     flow[src] = maxdata;
28
29     q.push(src);
30     while(!q.empty())
31     {
32         int index = q.front();
33         q.pop();
34
35         if(index == des)
36             break;
37         //层序寻找下一个可行通路
38         for(int i=0;i<arrsize;i++)
39         {
40             if(i!=src && cap[index][i]>0 && pre[i]==-1)
41             {
42                 pre[i]=index;                            //  保存当前结点的父结点
43                 flow[i]=min(cap[index][i],flow[index]);    //★更新从源结点到当前结点的当前剩余可用流量
44                 q.push(i);
45             }
46         }
47     }
48     if(pre[des]==-1)
49         return -1;
50     else
51         return flow[des];
52 }
53
54 int maxFlow(int src, int des)
55 //s最大流函数,迭代残量网络
56 {
57     int increasement,sumfolw = 0;
58     while((increasement = BFS(src,des)) != -1)
59     {
60         int cur = des;
61         while(cur != src)
62         {
63             int last = pre[cur];
64             cap[last][cur] -= increasement;
65             cap[cur][last] += increasement;
66             cur=last;
67         }
68         sumfolw += increasement;
69     }
70     return sumfolw;
71 }
72
73
74
75 int main()
76 {
77     freopen("C:\\Users\\lenovo\\Desktop\\工作\\华为挑战赛\\数据_E-K.txt","r",stdin);
78
79     for(short i=0;i<arrsize;i++)
80     for(short j=0;j<arrsize;j++)
81         cin>>cap[i][j];
82
83     //打印邻接矩阵
84     cout<<"邻接矩阵(有向图)为:"<<endl;
85     for(short i=0;i<arrsize;i++)
86     for(short j=0;j<arrsize;j++)
87     {
88         cout<<cap[i][j]<<" ";
89         if(j==arrsize-1)
90             cout<<endl;
91     }
92     cout<<endl;
93
94     memset(flow,0,sizeof(flow));
95     cout<<"最大流为:"<<maxFlow(0,3)<<endl<<endl;
96
97     fclose(stdin);
98 }

1.3 Bellman-Ford算法

由于在费用流中可能出现的负费用情况,必须考虑对含有负权边的有向图进行寻路的算法,一般采用Dijikstra或者Bellman-Ford算法,在这里也补充讨论下Bellman-Ford算法(下称B-F算法)。

基本的算法理解这篇文章对B-F算法介绍得已经很详细,另外《算导》Page379有更详细的证明可以参考 。在刘汝佳的《算法竞赛入门》中有进阶的算法实现,即使用FIFO队列辅助剪枝,这个方法在这篇文章中解释得很详细。

时间: 2024-08-30 04:30:47

关于网络流算法(2)的相关文章

网络流算法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方法及其多种实现 网络流 在上一章中我们讨论的主题是图中顶点之间的最短路径,例如公路地图上两地点之间的最短路径,所以我们将公路地图抽象为有向带权图.本章我们将对基于有向带权图的模型做进一步扩展. 很多系统中涉及流量问题,例如公路系统中车流量,网络中的数据信息流,供油管道的油流量等.我们可以将有向图进一步理解为"流

网络流算法模板

通过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),其实网络流最关键

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算法的基础上将随意取增广路径替换为取最短增广

关于网络流算法(3)

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

图论专题小结:网络流算法之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)对任

网络流算法与建模总结

[算法] 1.最大流 (1) 容量限制:对于∀u,v∈V ,要求 f (u,v) ≤ c(u,v). (2) 反对称性:对于∀u,v∈V ,要求 f (u,v) = − f (v,u). (3) 流量平衡:对于∀u∈V −{s,t},要求∑f(u,v)=0. dinic 根据残量网络计算层次图. 在层次图中使用DFS沿阻塞流(不考虑反向弧时的极大流 层次图中的)进行增广直到不存在增广路 重复以上步骤直到无法增广 int cur[N]; int vis[N],d[N],q[N],head,tail