题面:
把每两个点当成源汇,求N*(N-1)个最小割中不同的有多少个
N<=850
分析:
有这样一个结论:一张无向图不同的最小割最多有n-1个。
那么我们一定可以建出一棵树,使得这棵树中每两个点之间的最小割等于原图的两个点间的最小割。
我们倒也没必要吧这棵最小割树建出来。我们只需要做做样子,跑一下建树的过程就好,怎么办呢:
我们在原无向图中任选两个点S,T,求出S-T最小割,那么可以在S-T中间加一条权值等于最小割值得无向边
然后,分别对S属于的点集合和T属于的点集合递归做上面的过程,直到当前处理的集合只剩下一个点了
处理的方法就像分治那样就好。
注意建边时正反容量一样。注意每次要将边的流量恢复。记得要去重。
具体请看代码:
1 #include<bits/stdc++.h> 2 #define ms(a,x) memset(a,x,sizeof(a)) 3 using namespace std;int tot=0,n,m; 4 const int N=900,M=18000,inf=0x3f3f3f3f; 5 struct node{int y,z,nxt;}e[M];int h[N],c=1,q[M]; 6 int S,T,d[N],a[N],tmp[N],ans[N][N],v[1000000]; 7 void add(int x,int y,int z){ 8 e[++c]=(node){y,z,h[x]};h[x]=c; 9 e[++c]=(node){x,z,h[y]};h[y]=c; 10 } bool bfs(){ 11 int f=1,t=0;ms(d,-1);d[S]=0;q[++t]=S; 12 while(f<=t){ 13 int x=q[f++]; 14 for(int i=h[x],y;i;i=e[i].nxt) 15 if(d[y=e[i].y]==-1&&e[i].z) 16 d[y]=d[x]+1,q[++t]=y; 17 } return (d[T]!=-1); 18 } int dfs(int x,int f){ 19 if(x==T) return f;int w,tm=0; 20 for(int i=h[x],y;i;i=e[i].nxt) 21 if(d[y=e[i].y]==d[x]+1&&e[i].z){ 22 w=dfs(y,min(e[i].z,f-tm)); 23 if(!w) d[y]=-1;e[i].z-=w; 24 e[i^1].z+=w;tm+=w; 25 if(tm==f) return f; 26 } return tm; 27 } void solve(int l,int r){ 28 if(l>=r) return ;int sm=0; 29 for(int i=2;i<=c;i+=2) 30 e[i].z=e[i^1].z=(e[i].z+e[i^1].z)>>1; 31 S=a[l],T=a[r];int i,ql,qr; 32 while(bfs()) sm+=dfs(S,inf); 33 for(int i=1;i<=n;i++) if(~d[i]) 34 for(int j=1;j<=n;j++) 35 if(d[j]==-1) 36 ans[i][j]=ans[j][i]=min(ans[i][j],sm); 37 for(i=l,ql=l,qr=r;i<=r;i++) 38 if(~d[a[i]]) tmp[ql++]=a[i]; 39 else tmp[qr--]=a[i]; 40 for(int i=l;i<=r;i++) a[i]=tmp[i]; 41 solve(l,qr);solve(ql,r); 42 } int main(){ 43 scanf("%d%d",&n,&m);int an=0; 44 for(int i=1,x,y,z;i<=m;i++) 45 scanf("%d%d%d",&x,&y,&z),add(x,y,z); 46 for(int i=1;i<=n;i++) a[i]=i; 47 ms(ans,0x7f);solve(1,n); 48 for(int i=1;i<=n;i++) 49 for(int j=1+i;j<=n;j++) 50 v[++tot]=ans[i][j]; 51 sort(v+1,v+1+tot);v[0]=-inf; 52 for(int i=1;i<=tot;i++) 53 if(v[i]!=v[i-1]) an++; 54 printf("%d ",an);return 0; 55 }