转载请注明出处: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;
}