BZOJ 4519 不同的最小割 最小割树

题面:

  把每两个点当成源汇,求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\n",an);return 0;
55 }
最小割树

猜你喜欢

转载自www.cnblogs.com/Alan-Luo/p/10252570.html