网络最大流是指在一个网络流图中可以从源点流到汇点的最大的流量。求解网络最大流的常用算法可以分为增广路径算法和预推进算法。其中,预推进算法的理论复杂度优于增广路径算法,但是编码复杂度过高,且效率优势在很多时候并不是很明显,因此,经常使用的算法为增广路径算法。
增广路径算法主要有Fold-Fulkerson算法,Edmonds-Karp算法,Dinic算法,ISAP算法。其中,Fold-Fulkerson 是最基本的增广路径思想,不能算作严格的算法实现。
增广路径
增广路径算法的思想是每次从源点出发找到一条到达汇点的可行路径,那么从源点到汇点的网络流至少可以增加w(w为这条路径上的边的最小容量)。此时,将最大流增加w,这条路径称为增广路径,同时从源到汇沿着增广路径将经过的每条正向边(从源指向汇)的流量都减去w,并将每条边的反向边的流量加上w。这个操作就为增广操作。
不断的进行增广操作,直到无法从源到达汇停止。那么,此时得到最大流的流量。同时,可以得到在获得最大流的时候,每条边上的流量分布(只需要将原图中每条边的容量减去最后的残余网络
中每条边对应的流量即可)。
残余网络
在增广路径的过程中每次进行增广操作之后,得到的新图称为旧图的残余网络。
1. Fold-Fulkerson算法
Fold-Fulkerson算法就是朴素的增广路径思想。
求最大流的过程,就是不断找到一条从源到汇的路径,然后构造残余网络,再在残余网络的基础上寻找新的路径,使总流量增加,然后形成新的残余网络,在寻找新路径.... 直到某个残余网络上找不到从源到汇的路径为止。
每用DFS执行一次找路径,增广的操作,都会使得最大流增加,假设最大流为C,那么时间复杂度可以达到 C*(m+n), m为边的数目,n为顶点的数目。
2. Edmonds-Karp算法
Edmonds-Karp算法是在Fold-Fulkerson思想上进行改进:
每次寻找增广路径的时候,总是寻找一条从源到汇经过节点数目最少的路径,即最短路径。这是一种“最短增广路径” Shortest Augmenting Path(SAP)的算法。
在实现的时候,每次利用BFS搜索,找到一条从源到汇的最短路径,然后进行增广操作;再进行BFS....直到无法找到从源到汇的路径为止。
时间复杂度可以达到 n*m*m, n为顶点的数目,m为边的数目。
EdmondsKarp算法的实现
//增广操作 int Augment(int s, int t, int n){ memset(gVisited, false, sizeof(gVisited)); gVisited[s] = true; int find_path = false; queue<int>Q; Q.push(s); while (!Q.empty()){ int u = Q.front(); Q.pop(); //广度优先搜索一条从源点到汇点的路径 for (int i = 0; i < n; i++){ if (gGraph[u][i] > 0 && !gVisited[i]){ gVisited[i] = true; gPre[i] = u; if (i == t){