网络流问题:
设给定容量为Cv,w的有向图G = (V,E)。这些容量可以代表通过一个管道水的流量或在两个交叉路口之间的马路上的交通流量,有两个顶点,一个是s,称为发点,一个是t,称为收点。对于任意一条边(V,W),最多有流的Cv,w个单位可以通过,在既不是发点也不是收点的中间节点v,总的进入的流必须等于总的发出的流,最大流问题就是确定从发点s到收点t之间能够通过最大流量。
求解最大流的思路:
从图G开始构造一个流图Gf,Gf表示算法已经达到的流,开始时,Gf的所有边都没有流,我们希望当算法终止时,Gf包含最大流。
还要构造一个图Gr,称为残余图,它表示对每条边还能通过多少流。对于每一条边,我们可以从容量中减去当前的流而计算出残余的流。Gr的边叫做残余边。在每个阶段,寻找图Gr中从s到t的一条路径,这条路径叫做增长通路。其增广通路上两顶点之间最小的容量,即为该增长通路上的流量,在流量通过之后,在增长通路上添加与该路径方向相反,流量一样的反向弧,以使得流量可以回流。通过调整Gf和重新计算Gr做到这一点。当发现在Gr中没有从s到t的路径时算法终止。
EK算法:使用BFS(广度搜索优先)来寻找增长通路,如果存在一条增张通路,则对残余图进行更新(添加反向弧),记录下以通过的流量。如果找不到,则图中已经没有流量了,算法结束
#defind MAXVERTEX 100
int path[MAXVERTEX]; //记录增长通路的路径
int BFS(Graph G,int s,int t) {
int i, flow[MAXVERTEX], v;
linkQueue Q;
Q = createQueue(); //创建队列
for (i = 0; i < G->Nv;i++) {
//初始化路径
path[i] = -1;
}
flow[s] = MAXNUM; //到自身的流量为无穷大
EeueueQueue(s, Q); //入队列
while (!IsEmpty(Q)) {
v = frontAndDeueue(Q); //出队列
for (i = 0; i < G->Nv;i++) {
//搜索所有对顶点v相连接的顶点,如果有流量,加入路径记录下来
if (i != s && G->Graph[v][i] > 0 && path[i] == -1) {
path[i] = v;
flow[i] = flow[v] < G->Graph[v][i] ? flow[v] : G->Graph[v][i];
EeueueQueue(i, Q); //入队列
}
}
}
if (path[t] == -1) { //为-1表示,为找到增长通路
return -1;
}
return flow[t]; //返回增长通路上的最大流量
}
int EK(Graph G, int s,int t) {
//在图G中寻找发点s到收点t的最大流
int result, d, p; //result记录当前最大流的流量,d记录一条增长通路的流量
result = 0;
while (1) {
d = BFS(G, s, t); //返回增长通路的最大流量
if (d == -1) {
//d为-1代表没有增长通路
break;
}
p = t;
//根据增长通路,更新残留图和流量
while (p != s) {
G->Graph[path[p]][p] -= d; //增长通路减去通过的流量
G->Graph[p][path[p]] += d; //添加反向弧
p = path[p]; //指针向上寻找路径
}
result += d;
}
return result;
}