样例输入:
6 10
0 1 8 2
0 2 4 3
1 3 2 2
1 4 2 2
2 1 4 2
2 3 1 1
2 4 4 0
3 4 6 0
3 5 9 3
4 5 7 2
样例输出:
0->1 : 4
0->2 : 4
1->3 : 2
1->4 : 2
2->1 : 0
2->3 : 1
2->4 : 3
3->4 : 0
3->5 : 3
4->5 : 5
maxFlow : 8
#include <cstdio> #include <cmath> #include <cstring> #define MAXN 1000 //顶点个数最大值 #define INF 1000000 //无穷大 #define MIN(a,b) ((a)<(b)?(a):(b)) struct ArcType //弧结构 { int c, f; //容量,流量 }; ArcType Edge[MAXN][MAXN]; //邻接矩阵(每个元素为ArcType类型) int n, m; //顶点个数和弧数 int flag[MAXN]; //顶点状态:-1-未标号,0-已标号未检查,1-已标号已检查 int prev[MAXN]; //标号的第一个分量:指明标号从哪个顶点得到,以便找出可改进量 int alpha[MAXN]; //标号的第二个分量:可改进量α int queue[MAXN]; //相当于BFS算法中的队列 int v; //从队列里取出来的队列头元素 int qs, qe; //队列头位置,队列尾位置 int i, j; //循环变量 void ford( ) { while( 1 ) //标号直至不存在可改进路 { //标号前对顶点状态数组初始化 memset( flag, 0xff, sizeof(flag) ); //将3个数组各元素初始化为-1 memset( prev, 0xff, sizeof(prev) ); memset( alpha, 0xff, sizeof(alpha) ); flag[0] = 0; prev[0] = 0; alpha[0] = INF; //源点为已标号未检查顶点 qs = qe = 0; queue[qe] = 0; qe++; //源点(顶点0)入队列 //qs<qe表示队列非空, flag[n-1]==-1表示汇点未标号 while( qs<qe && flag[n-1]==-1 ) { v = queue[qs]; qs++; //取出队列头顶点 for( i=0; i<n; i++ ) //检查顶点v的正向和反向"邻接"顶点 { if( flag[i]==-1 ) //顶点i未标号 { //"正向"且未"满" if( Edge[v][i].c<INF && Edge[v][i].f < Edge[v][i].c ) { flag[i] = 0; prev[i] = v; //给顶点i标号(已标号未检查) alpha[i] = MIN( alpha[v], Edge[v][i].c - Edge[v][i].f ); queue[qe] = i; qe++; //顶点i入队列 } else if( Edge[i][v].c<INF && Edge[i][v].f > 0 ) //"反向"且有流量 { flag[i] = 0; prev[i] = -v; //给顶点i标号(已标号未检查) alpha[i] = MIN( alpha[v], Edge[i][v].f ); queue[qe] = i; qe++; //顶点i入队列 } } } flag[v] = 1; //顶点v已标号已检查 }//end of while( qs<qe && flag[n-1]==-1 ) //当汇点没有获得标号,或者汇点的调整量为0,应该退出while循环 if( flag[n-1]==-1 || alpha[n-1]==0 ) break; //当汇点有标号时,应该进行调整了 int k1 = n-1, k2 = abs( prev[k1] ); int a = alpha[n-1]; //可改进量 while( 1 ) { if( Edge[k2][k1].f<INF ) //正向 Edge[k2][k1].f = Edge[k2][k1].f + a; else Edge[k1][k2].f = Edge[k1][k2].f - a; //反向 if( k2==0 ) break; //调整一直到源点v0 k1 = k2; k2 = abs( prev[k2] ); }//end of while( 1 ) }//end of while( 1 ) //输出各条弧及其流量,以及求得的最大流量 int maxFlow = 0; for( i=0; i<n; i++ ) { for( j=0; j<n; j++ ) { if( i==0 && Edge[i][j].f<INF ) //求源点流出量,即最大流 maxFlow += Edge[i][j].f; if( Edge[i][j].f<INF ) printf( "%d->%d : %d ", i, j, Edge[i][j].f ); } } printf( "maxFlow : %d ", maxFlow ); } void main( ) { int u, v, c, f; //弧的起点、终点、容量、流量 scanf( "%d%d", &n, &m ); //读入顶点个数n和弧数m for( i=0; i<n; i++ ) //初始化邻接矩阵中各元素 { for( j=0; j<n; j++ ) Edge[i][j].c = Edge[i][j].f = INF; //INF表示没有直接边连接 } for( i=0; i<m; i++ ) //读入每条弧 { scanf( "%d%d%d%d", &u, &v, &c, &f ); //读入边的起点和终点 Edge[u][v].c = c; Edge[u][v].f = f; //构造邻接矩阵 } ford( ); //标号法求网络最大流 }