最大流EdmondsKarp算法

来源:互联网 发布:英语文章带翻译软件 编辑:程序博客网 时间:2024/05/29 14:27

转载请注明出处:http://blog.csdn.net/Bule_Zst/article/details/78329115


问题阐述:

告诉你n个节点,以及m条边(有向边),已知每条边的容量和当前流量,求从第一个节点到第n个节点的最大流量。

求法:

根据已知的容量和流量可以计算出每条边目前还可以通过的流量,然后宽搜出一条从1到n的路(还可通过的流量必须大于0才认为这条边存在),找到这条路上最小的可通过的流量,然后更新答案以及这些边上的流量。循环操作直到不存在一条路从1到n。

这样做有一个问题,那就是,如果有多条路从1到达n,而我们可以选择其中的一些路来计算流量,那么如何选取就很重要。

举个例子

有4个结点,5条路,默认当前流量都为0,如果不为0,只需要把容量相应减少即可
起点,终点,容量
1 2 1
1 3 3
2 3 2
2 4 3
3 4 1

如果搜索到1-2-3-4这条路,然后将相应边更新,就会发现,不存在其他的从1到n的路了,然而答案显然不是1,因为1-3-4与1-2-4可以组成流量2。

因此,EK算法引入了一个错误纠正机制,正如上面的例子,其实找到1-2-3-4这条路是错误的,不应该选择这条路,那么怎么办呢,更新1-2-3-4这些边的同时,加入一些反向边,1-2-3-4这条路,把每条边的容量减1的同时,让反向边的容量加1,这样做之后,再去搜索从1到n的路就会发现多出来了一条,1-3-2-4,这样流量就变成2了。

走1-3-2-4这条路的本质就是:先走1-2-3-4这条路,然后发现出错了,因此不走1-2-3-4这条路,转而走1-2-4与1-3-4这两条路,走3-2这条边其实就是把之前的1-2-3-4这条路断开来,剩下1-2与3-4,然后与1-3-2-4中的1-3、2-4组合,形成新的路:1-2-4、1-3-4。

HDU-1532代码:

// @Team    : nupt2017team16// @Author  : Zst#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <vector>#include <queue>#include <cmath>#include <algorithm>#include <map>using namespace std;#define LL          long long#define MOD         1000000007#define MEM(a,x)    memset(a,x,sizeof(a))#define FILL(a,n,x) fill(a,a+n,x)#define INF         0x3f3f3f3f#define pb          push_back#define FOR(i,a,b)  for( int i = ( a ); i <= ( b ); ++i )#define WHILE()     int T;scanf( "%d", &T );while( T-- )const int N = 200+7;int n, m;int C[N][N];int pre[N];bool vis[N];bool bfs() {    MEM( pre, -1 );    pre[1] = 1;    queue<int> q;    q.push( 1 );    MEM( vis, false );    vis[1] = true;    while( !q.empty() ) {        int u = q.front();        q.pop();        FOR( i, 1, n ) {            if( C[u][i] > 0 && vis[i] != true ) {                q.push( i );                vis[i] = true;                pre[i] = u;                if( i == n ) {                    return true;                }            }        }    }    return false;}int solve() {    int ans = 0;    while( bfs() ) {        int mins = INF;        for( int i = n; i != 1; i = pre[i] ) {            mins = min( mins, C[pre[i]][i] );        }        for( int i = n; i != 1; i = pre[i] ) {            C[pre[i]][i] -= mins;            C[i][pre[i]] += mins;        }        ans += mins;    }    return ans;}int main(){    // freopen( "1532.txt", "r", stdin );    while( scanf( "%d%d", &m, &n ) != EOF ) {        MEM( C, 0 );        int u, v, w;        FOR( i, 0, m-1 ) {            scanf( "%d%d%d", &u, &v, &w );            C[u][v] += w;        }        printf( "%d\n",solve() );    }    return 0;}

参考文章:http://blog.sina.com.cn/s/blog_6cf509db0100uy5n.html

原创粉丝点击