#include<bits/stdc++.h> using namespace std; //最小割就是把起点及其他分成一个城市,终点及其他分成一个城市,当两个城市之间的线路的流量都满载时,的分法。 //当最大流算法结束时,flag数组不是0的都是从s可达的,而且不可达的原因是没有残余了,所以就找到了最小割 const int maxn=1001; int G[maxn][maxn],pre[maxn],n,m,flow[maxn][maxn],a[maxn];//flow是当前的流量 a 代表到某个点的最小残余流量 //通过前驱数组求一条路径,当然结果可能会多了不是这条路径上的点的前驱,因为不一定能一次到 int flg[maxn]; int maxflow(int s,int t){ int f=0; //使用bfs,因为每次都要找一条路径,bfs快 memset(flow,0,sizeof(flow)); while(1){ queue<int> q; q.push(s); memset(flg,0,sizeof(flg)); memset(pre,0,sizeof(pre)); memset(a,0x3f3f3f3f,sizeof(a)); flg[s]=1;//必须设置 while(!q.empty()){ int x=q.front(); q.pop(); for(int i=1;i<=n;i++){ //有流量剩余 //因为有残量才能遍历,所以t可能遍历不到 if(!flg[i]&&G[x][i]!=0&&G[x][i]>flow[x][i]){ pre[i]=x; flg[i]=1; //到i的最小=到x的最小 和 x到i的 小的那个 a[i]=min(a[x],G[x][i]-flow[x][i]);//不用整体的min,因为那条路径不一定在s->t上 //注意,他没有对a[i]再取最小值,这样就可以保证pre和a[t]是对应的同一条边 //当然也可以,这个就是取所有可达边的最小值残余的 最小值 // if(a[i]>min(a[x],G[x][i]-flow[x][i])){ // a[i]=min(a[x],G[x][i]-flow[x][i]); // pre[i]=x; // } // if(i==t) break; //两层循环无法退出 q.push(i); } } if(x==t) break;//我觉得可以提前终止,如果遍历到了t } cout<<a[t]<<endl; //其实当残量为0时,根本遍历不到 if(a[t]==0x3f3f3f3f){ //输出最小割 cout<<"minimum ge "; cout<<"Set S "; for(int i=1;i<=n;i++) if(flg[i]) cout<<i<<" ";cout<<endl; cout<<"Set T "; for(int i=1;i<=n;i++) if(!flg[i]) cout<<i<<" ";cout<<endl; } if(a[t]==0x3f3f3f3f) return f;//没路径退出 //有残余,对于pre找到的路径上的每个点,都更新flow for(int i=t;i!=s;i=pre[i]){ //注意到s停,因为用到pre flow[pre[i]][i]+=a[t]; flow[i][pre[i]]-=a[t];//别忘了减,根据流量的定义,对于a-> b->a的边有用 } f+=a[t]; } } int main() { cin>>n>>m; memset(G,0,sizeof(G)); for(int i=0;i<m;i++){ int x,y,z; cin>>x>>y>>z; G[x][y]=z; } cout<<maxflow(5,6)<<endl; return 0; }