我们有某些结论,本质不同的最小割一共有n-1个。
在这颗最小割树上,我们有两种点集,一种是源点点集,一种是汇点点集
我们做一次dinic后被增广到的地方就属于源点点集,否则属于汇点点集。这两个点集之间我们任意选的s和t之间的连边就是最小割的大小
然后我们分治递归两个子树来构建这颗最小割树
性质还有任意两个点之间的路径的最小权值就是这两点的最小割
然后这就成为了分治最小割的裸题了
/* *********************************************** Author :BPM136 Created Time :2016/4/20 14:54:49 File Name :A.cpp ************************************************ */ #include<iostream> #include<cstdio> #include<algorithm> #include<cstdlib> #include<cmath> #include<cstring> #include<iomanip> #include<bitset> #include<queue> #include<ctime> #include<set> #include<utility> #include<vector> #include<functional> #include<numeric> #include<memory> #include<iterator> #define LL long long #define DB double #define LB long double #define UL unsigned long #define ULL unsigned long long #define get(a,i) a&(1<<(i-1)) #define PAU putchar(0) #define ENT putchar(32) #define clr(a,b) memset(a,b,sizeof(a)) #define fo(_i,_a,_b) for(int _i=_a;_i<=_b;_i++) #define fd(_i,_a,_b) for(int _i=_a;_i>=_b;_i--) #define efo(_i,_a) for(int _i=last[_a];_i!=0;_i=e[_i].next) #define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout); #define mkd(x) freopen(#x".in","w",stdout); #define setlargestack(x) int size=x<<20;char *p=(char*)malloc(size)+size;__asm__("movl %0, %%esp\n" :: "r"(p)); #define end system("pause") using namespace std; LL read() { LL f=1,d=0;char s=getchar(); while (s<48||s>57){if (s==45) f=-1;s=getchar();} while (s>=48&&s<=57){d=d*10+s-48;s=getchar();} return f*d; } LL readln() { LL f=1,d=0;char s=getchar(); while (s<48||s>57){if (s==45) f=-1;s=getchar();} while (s>=48&&s<=57){d=d*10+s-48;s=getchar();} while (s!=10) s=getchar(); return f*d; } inline void write(LL x) { if(x==0){putchar(48);return;}if(x<0)putchar(45),x=-x; int len=0,buf[20];while(x)buf[len++]=x%10,x/=10; for(int i=len-1;i>=0;i--)putchar(buf[i]+48);return; } inline void writeln(LL x){write(x);ENT;} #define N 855 #define M 8505 #define MAXW 100005 const int inf = 0x7fffffff / 2 - 1; struct edge { int y,next,f; }e[M*10]; int last[N],ne=1; int cur[N]; #define efoc(i,x) for(int i=cur[x];i!=0;i=e[i].next) int n,m; int Ans[N],Ansnum=0; int a[N]; int tmp[N]; void add(int x,int y,int f){ e[++ne].y=y;e[ne].f=f;e[ne].next=last[x];last[x]=ne; } void add2(int x,int y,int f){ add(x,y,f);add(y,x,f); } void get_this(){ for(int k=2;k<=ne;k+=2){ e[k].f=e[k^1].f=(e[k].f+e[k^1].f)>>1; } } int high[N]; bool bfs(int s,int t){ queue<int>q; fo(i,0,n)high[i]=-1; q.push(s);high[s]=0; while(!q.empty()){ int now=q.front();q.pop(); efo(i,now){ if(high[e[i].y]==-1&&e[i].f){ high[e[i].y]=high[now]+1; q.push(e[i].y); } } } return high[t]!=-1; } int dfs(int x,int f,int T){ if(x==T||f==0)return f; int w,used=0; efoc(i,x){ if(high[e[i].y]==high[x]+1){ w=f-used; w=dfs(e[i].y,min(w,e[i].f),T); e[i].f-=w;e[i^1].f+=w; used+=w; if(e[i].f) cur[x]=i; if(used == f)return used; } } if(!used)high[x]=-1; return used; } int dinic(int S,int T){ int ret=0; while(bfs(S,T)){ fo(i,1,n)cur[i]=last[i]; ret+=dfs(S,inf,T); } return ret; } bool mark[N]; void dfs_flow(int x){ mark[x]=1; efo(i,x){ if(mark[e[i].y]==0&&e[i].f){ dfs_flow(e[i].y); } } } void solve(int l,int r){ if(l==r)return; get_this(); int ret=dinic(a[l],a[r]); Ans[++Ansnum]=ret; memset(mark,0,sizeof(mark)); dfs_flow(a[l]); int L=l,R=r; fo(i,l,r){ if(mark[a[i]])tmp[L++]=a[i]; else tmp[R--]=a[i]; } fo(i,l,r)a[i]=tmp[i]; solve(l,L-1);solve(R+1,r); } int main() { file(A); n=read(),m=read(); fo(i,1,m){ int x=read(),y=read(),f=read(); add2(x,y,f); } fo(i,1,n)a[i]=i; solve(1,n); sort(Ans+1,Ans+Ansnum+1); int ans=1; fo(i,2,Ansnum){ if(Ans[i]!=Ans[i-1])ans++; } writeln(ans); return 0; }