最小割树

Posted emiya-wjk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小割树相关的知识,希望对你有一定的参考价值。

知识点

定理:

无向图任意两点间的最小割,不同的只有(n-1)个。

实现:
1.在点集中任取两点(S,T),求最最小割(C),在最小割树中加入边(S,T,|C|)

2.把点集分为与(S)联通的集合和不与(S)联通的集合,递归进行操作(1),直至点集大小为(1)时停止。

题目

【ZJOI2011】最小割

【CQOI2016】不同的最小割

//【CQOI2016】不同的最小割 代码
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#include<set>
#define MAXN 0x7fffffff
typedef long long LL;
const int N=1005,M=8505;
using namespace std;
inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;}
int n,m,id[N];
set<int>ans;
namespace GHT{
    int h[N],cnt;
    struct node{int to,next,flow,pair;}g[M<<2];
    void AddEdge(int x,int y,int z){
        g[++cnt].to=y,g[cnt].next=h[x],h[x]=cnt,g[cnt].flow=z,g[cnt].pair=cnt+1;
        g[++cnt].to=x,g[cnt].next=h[y],h[y]=cnt,g[cnt].flow=z,g[cnt].pair=cnt-1;
    }
    
    int S,T;
    int dis[N],GAP[N],col[N];
    void Init(){
        static int q[N];
        fill(dis+1,dis+1+n,0),fill(GAP+1,GAP+1+n,0);
        int l=0,r=1;q[++l]=T,++GAP[dis[T]=1];
        while(l<=r){
            int x=q[l++];
            for(int i=h[x];i;i=g[i].next){
                int to=g[i].to;
                if(!dis[to])++GAP[dis[to]=dis[x]+1],q[++r]=to; 
            }
        }
    }
    int Dfs(int x,int Maxf){
        if(x==T||!Maxf)return Maxf;
        int ret=0;
        for(int i=h[x];i;i=g[i].next){
            int to=g[i].to;
            if(g[i].flow&&dis[x]==dis[to]+1){
                int dlt=Dfs(to,min(g[i].flow,Maxf-ret));
                g[i].flow-=dlt,g[g[i].pair].flow+=dlt;
                ret+=dlt;if(dis[S]==n+1||ret==Maxf)return ret;
            }
        }
        if(!(--GAP[dis[x]]))dis[S]=n+1;
        else ++GAP[++dis[x]];
        return ret;
    }
    int SAP(){
        Init();
        int ans=Dfs(S,MAXN);
        while(dis[S]<=n)ans+=Dfs(S,MAXN);
        return ans;
    }
    void Paint(int x){
        col[x]=1;
        for(int i=h[x];i;i=g[i].next)
            if(g[i].flow&&!col[g[i].to])Paint(g[i].to);
    } 
    void Build(int l,int r){
        if(l==r)return;
        for(int i=1;i<=cnt;i+=2)g[i].flow=g[i+1].flow=(g[i].flow+g[i+1].flow)>>1;
        S=id[l],T=id[r];
        ans.insert(SAP());
        fill(col+1,col+1+n,0),Paint(S);
        static int tmp[N];
        int L=l,R=r;
        for(int i=l;i<=r;i++){
            if(col[id[i]])tmp[L++]=id[i];
            else tmp[R--]=id[i];
        }
        for(int i=l;i<=r;i++)id[i]=tmp[i];
        Build(l,L-1),Build(R+1,r);
    }
}
int main(){
    n=Getint(),m=Getint();
    for(int i=1;i<=m;i++){
        int x=Getint(),y=Getint(),z=Getint();
        GHT::AddEdge(x,y,z);
    }
    for(int i=1;i<=n;i++)id[i]=i;random_shuffle(id+1,id+1+n);
    GHT::Build(1,n);
    cout<<ans.size();
    return 0;
}

以上是关于最小割树的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces 343E 最小割树

bzoj4435: [Cerc2015]Juice Junctions(最小割树+hash)

最小割树和网络流水题

最小割树

[bzoj2229][Zjoi2011]最小割_网络流_最小割树

bzoj2229: [Zjoi2011]最小割(最小割树)