#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; #define Size 200 int Gra[Size+1][Size+1];// 由于是单向边 所以一个矩阵可以表示一个带有反向边的残余网络 bool Visited[Size+1]; int Pre[Size+1]; // 前驱节点 用来形成一条从源点到汇点的路径 int N, M, S, E, C;// 输入数据 int EK() { memset( Visited, 0, sizeof(Visited) ); Pre[1] = 0; Visited[1] = true; queue<int>Que; bool FindPath = false; // 标记是否找到 一条增广路径 Que.push(1); while( !Que.empty() ) { int T = Que.front(); Que.pop(); for( int i=1; i<=M; i++ )// 广搜遍历所有顶点 if( Gra[T][i]>0 && !Visited[i] ) { Pre[i] = T; Visited[i] = true; if( i==M ) { FindPath = true; Que.empty(); // 清空 以便 跳出while break; } else Que.push(i); } } if( !FindPath ) return 0; // 未找到一条增广路径 int RateFlow = 1<<30; int V = M; while( Pre[V] ) // 追溯 路径上的最小值 即最终汇流量 { RateFlow = min( RateFlow, Gra[Pre[V]][V] ); V = Pre[V]; } V = M; while( Pre[V] ) { Gra[Pre[V]][V] -= RateFlow; Gra[V][Pre[V]] += RateFlow; V = Pre[V]; } return RateFlow; } int main() { while( ~scanf( "%d%d", &N, &M ) ) { memset( Gra, 0, sizeof(Gra) ); for( int i=0; i<N; i++ ) { scanf( "%d%d%d", &S, &E, &C ); Gra[S][E] += C; // 有重边 } int ans = 0; int n; while( n=EK() ) ans += n; printf( "%d\n", ans ); } return 0; }
时间: 2024-10-03 14:56:08