杭电3549就是一道最经典的最大流问题,基本上就是套模板。输入两个数 点数M 路径数N,然后输入N行。每行有三个数x,y,z。分别代表头结点尾节点和路径长度。 网络流是个有向图。
下是最大流问题的KM算法,通过反复找增广路径来获得最大流量。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define INF 0x7f7f7f7f
using namespace std;
int flow[205][205]/*记录路径流*/, cap[205][205]/*路径的容量*/, p[205]/*父路径*/, c[205]/*残留路径*/;
int maxflow;
int M;
void BFS()
{
queue<int>q;
maxflow=0;
bool there=1;//初始化这里有增广路径
memset( flow, 0, sizeof( flow ) );
while(there)//找增广路径的循环,没有增广路径则跳出
{
memset( p, 0, sizeof( p ) );
memset( c, 0, sizeof( c ) );
c[1]= INF, p[1]=-1;
q.push( 1 );
while( !q.empty() )//广搜的循环
{
int pos= q.front();
q.pop();
for( int i=1; i<= M; ++i )
{
if( !c[i]&& flow[pos][i]< cap[pos][i] ) // 残留流量为0并且流入这点的路径中流量比容量小
{
c[i]= min( c[pos], cap[pos][i]- flow[pos][i] ); // 选取当前管道残留容量和截止到上一次的路径残留容量之间的较小者,可以看作是一种更新
//即该增广路径的残留容量是有路径中残留容量最小的管道决定的
//每一次广搜都要把能使残留流量最小的流储存,在这里更新流会造成破坏,存入不是最优解
p[i]= pos; // 记录父亲路径
q.push( i );
}
}
}
if( c[M]==0 )//没有残留路径到达N点,则跳出循环结束
there=0;
maxflow+= c[M];
int pos= M;
while(there&& pos!=1 )//从终点倒序更新路径流量,每次只更新
{
flow[ p[pos] ][ pos ]+= c[M];
flow[ pos ][ p[pos] ]-= c[M];
pos= p[ pos ];
}
}
}
int main()
{
int N,maxflow, ca=0, T;
scanf( "%d", &T );
while( T-- )
{
scanf( "%d %d", &M, &N );
memset( cap, 0, sizeof( cap ) );
for( int i=1; i<= N; ++i )
{
int x, y, z;
scanf( "%d %d %d", &x, &y, &z );
cap[x][y]+= z;
}
BFS();
printf( "Case %d: %d\n", ++ca, maxflow );
}
return 0;
}
/**
6 8
1 2 4
1 3 5
2 4 2
2 5 4
3 4 1
3 5 4
4 6 3
5 6 6
*/