您的位置:首页 > 其它

最大流 - Edmonds-Karp 增广路算法

2013-01-04 17:01 507 查看
如图1所示,为该图初始状态,绿色线条为正流量权重,灰色线条为反流量权重。在此算法中,每当正向流量减少N时,反向流量则增加N,反之亦然。



找到一条从s->t的路径:s->v1->v2->t,该路径的最大流量为2,则更新完流量以后的图如下图所示。



找到一条由s->t的路径:s->v1->t,该路径的流量限制为2,则更新完流量以后如下图所示:



找到另外一条由s->的路径:s->v2->v1->t,该路径的流量限制为2。则更新完流量以后如图所示:



找到另一条由s->t的路径:s->v2->t,该路径的流量限制为2,则更新完流量以后如下图所示:



找不到其它由s->t的路径,则增广结束,找到最大流值为8。

可以看出,此算法的核心步骤为如何找到一条由s->t的增广路径,并得到该路径上的流量限制。我们很容易想到用DFS进行路径的搜索,但是在很多情况下DFS搜索会很慢,在EK算法中,我们采用BFS进行合法路径的搜索。

下面是个复杂点的例子:



最大流:



程序代码:

/*
* Demo source code for Edmonds-Karp max stream algorithm
*
* ek_max_stream.cc
*
* Created on: Jan 4, 2013
*      Author: root
*/
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;

//Suppose there are only 10 vertexes at most
const int MAX_VERTEX = 10;
const int MAX_VALUE = 1<<30;

int graph[MAX_VERTEX][MAX_VERTEX];

int vertex_number;
queue<int> fifo_queue;
//store current vertex's prefix vertex
int prefix[MAX_VERTEX];
//store stream size of path which start s and end with current node
int stream[MAX_VERTEX];

/**
* v0-s
* v1-v1
* v2-v2
* v3-t
*/
void BuildGraph() {
vertex_number=6;
for (int i=0; i<MAX_VERTEX; i++)
memset(graph[i], -1, sizeof(graph[i]));
//Forward stream define
graph[0][1] = 16;
graph[0][2] = 13;
graph[1][3] = 12;
graph[2][3] = 0;
graph[1][2] = 10;
graph[2][4] = 14;
graph[4][3] = 7;
graph[4][5] = 4;
graph[3][5] = 20;
//Reverse stream define
graph[1][0] = 0;
graph[2][0] = 0;
graph[3][1] = 0;
graph[3][2] = 9;
graph[2][1] = 4;
graph[4][2] = 0;
graph[3][4] = 0;
graph[5][4] = 0;
graph[5][3] = 0;
}

void ClearQueue() {
while (!fifo_queue.empty())
fifo_queue.pop();
}

int Min(int a, int b) {
return a < b ? a : b;
}

void SearchTarget(int start, int stop) {
if (start == stop)
return;
int max_stream=0;
while (true) {
ClearQueue();
memset(prefix, -1, sizeof(prefix));
memset(stream, 0, sizeof(stream));
stream[start] = MAX_VALUE;

//start BFS
fifo_queue.push(start);
while (!fifo_queue.empty()) {
int current = fifo_queue.front();fifo_queue.pop();
for (int i=0; i<vertex_number; i++)
if (i != current && graph[current][i] > 0 && prefix[i]==-1) {
fifo_queue.push(i);
prefix[i] = current;
//store current path's stream size
stream[i] = min(stream[current], graph[current][i]);
if (i == stop) {
break;
}
}

//break if we have found target node
if (stream[stop])
break;
}

for (int i=0; i<vertex_number; i++)
printf("[path] %d->%d\n", prefix[i], i);

if (stream[stop]) {
int max_value = stream[stop];
max_stream += max_value;
//modify graph stream value
for (int current=stop; current!=start; current = prefix[current]) {
printf("%d->%d, current stream is %d, will use %d \n", prefix[current], current, graph[prefix[current]][current], max_value);
graph[prefix[current]][current] -= max_value;
graph[current][prefix[current]] += max_value;
}
} else {
printf("No available path found, exit now\n");
break;
}
}
printf("Max stream size is:%d\n", max_stream);
}

int main(int argc, char** argv) {
BuildGraph();
SearchTarget(0, 5);
return 0;
}


运行结果:

[path] -1->0
[path] 0->1
[path] 0->2
[path] 1->3
[path] 2->4
[path] 3->5
3->5, current stream is 20, will use 12
1->3, current stream is 12, will use 12
0->1, current stream is 16, will use 12
[path] 1->0
[path] 0->1
[path] 0->2
[path] 4->3
[path] 2->4
[path] 4->5
4->5, current stream is 4, will use 4
2->4, current stream is 14, will use 4
0->2, current stream is 13, will use 4
[path] 1->0
[path] 0->1
[path] 0->2
[path] 4->3
[path] 2->4
[path] 3->5
3->5, current stream is 8, will use 7
4->3, current stream is 7, will use 7
2->4, current stream is 10, will use 7
0->2, current stream is 9, will use 7
[path] 1->0
[path] 0->1
[path] 0->2
[path] -1->3
[path] 2->4
[path] -1->5
No available path found, exit now
Max stream size is:23
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: