2017 青岛网络赛 Smallest Minimum Cut 最大流最小割问题, (加深理解最大流问题)
定理1: 最大流最小割定量: 在任何的网络中,最大流的值等于最小割的容量
定理2: 在任何网络中,如果f是一个流,CUT(S,T)是一个割,且f的值等于割CUT(S,T)的容量,那么f是一个最大流
结论1:最大流时,最小割cut(S,T)中,正向割边的流量=容量,逆向割边的流量为0。否则还可以增广。
推论1:如果f是网络中的一个流,CUT(S,T)是一个割,那么f的值不超过割CUT(S,T)的容量。
推论2:网络中的最大流不超过任何割的容量
最大流 在找增广路时 , 当找不到时 , 那么此时就是最大流量;
定理的意思, 最小割的容量= 最大流, 我们这样来理解;
(1)当跑完最大流时候,最小割必定满流,即最小割每条边流量都等于容量
(2) 跑完最大流的时候,用每条边的容量减去流量便是此时的残量网络
(3)跑完最大流后,再通过reduce,clearflow操作,此时再求最大流,结果为0
这道题的意思在 最大流基础上的 最小割边数目 使得 s 和 t 变成 独立的点,
从结果分析,
在建图的时候 权值* 一个大数 +1 然后 跑出来的最大流 %这个大数 就是 结果 ;
我询问了 多人, 得到的回答是;
边权值 * 一个大数%那个大数是0,你+1的话,如果这是满条边流的,%那个大数是1,设最小割的最少边数是x,那么流量%那个大数==x
#include <iostream> #include <stdio.h> #include <algorithm> #include <cmath> #include <math.h> #include <cstring> #include <string> #include <queue> #include <stack> #include <stdlib.h> #include <list> #include <map> #include <set> #include <bitset> #include <vector> #define mem(a,b) memset(a,b,sizeof(a)) #define findx(x) lower_bound(b+1,b+1+bn,x)-b #define FIN freopen("input.txt","r",stdin) #define FOUT freopen("output.txt","w",stdout) #define S1(n) scanf("%d",&n) #define SL1(n) scanf("%I64d",&n) #define S2(n,m) scanf("%d%d",&n,&m) #define SL2(n,m) scanf("%I64d%I64d",&n,&m) #define Pr(n) printf("%d\n",n) using namespace std; typedef long long ll; const double PI=acos(-1); const int INF=0x3f3f3f3f; const double esp=1e-6; const int maxn=1e4+5; const int MOD=1e9+7; const int mod=1e9+7; int dir[5][2]={0,1,0,-1,1,0,-1,0}; struct node{ int v,w,next; //u v 从 u-v 权值为w }edge[maxn]; int head[maxn],num[maxn],start,END,cnt,sum; void init() { cnt=0; mem(head,-1); } void add(int u,int v,int w) { /* 根据题意建立有向图或无向图, 有向图反路0 无向图反路一样 */ edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].w=0; edge[cnt].next=head[v]; head[v]=cnt++; } int bfs() { queue<int>Q; mem(num,0); num[start]=1; Q.push(start); while(!Q.empty()) { int t=Q.front(); Q.pop(); if(t==END) return 1; for(int i=head[t];i!=-1;i=edge[i].next)// 链式前向星访问找增广路 { int t1= edge[i].v;//下一个节点 int t2= edge[i].w;// 当前点 权值 if(t2&&num[t1]==0)// 当前点存在 并且下一个点没有访问 { num[t1]=num[t]+1;// 点=1 if(t1==END)// 结束 return 1; Q.push(t1); } } } return 0; } int dfs(int u,int maxflow) { if(u==END) return maxflow; int res=0; for(int i=head[u];i!=-1;i=edge[i].next) { int t1=edge[i].v;// 下一个节点 int t2=edge[i].w;// 当前节点 if(t2&&num[t1]==num[u]+1) { int temp=dfs(t1,min(maxflow-res,t2));// 选择流 小的一部分 edge[i].w-=temp;// 正向减少 edge[i^1].w+=temp;//反向增加 res+=temp; if(res==maxflow) return res; } } if(!res) num[u]=-1; return res; } void Dinic() { int ans=0; while(bfs()) { ans+=dfs(start,INF); } printf("%d\n",ans%10005); } int main() { int t; cin>>t; while(t--) { init(); int n,m; int x,y,z; scanf("%d %d",&n,&m); scanf("%d %d",&start,&END); for(int i=1;i<=m;i++) { scanf("%d %d %d",&x,&y,&z); add(x,y,z*10005+1); } Dinic(); } return 0; }
岂曰无衣?与子同袍。王于兴师,修我戈矛。与子同仇!
岂曰无衣?与子同泽。王于兴师,修我矛戟。与子偕作!
岂曰无衣?与子同裳。王于兴师,修我甲兵。与子偕行!