• 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
    ",an);return 0;
    55 }
    最小割树
  • 相关阅读:
    修改表的定义
    DataFrame.groupby()函数
    有限差分法
    Python之pandas库
    类:实验2家中的电视
    函数:使用函数指针操作函数
    函数:函数操作结构体通过按值传递以及按址传递,使用动态内存
    函数:使用数组名作为函数参数进行操作
    函数:使用递归实现阶乘
    函数:通过按值传递及传递结构地址操作结构
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10252570.html
Copyright © 2020-2023  润新知