[bzoj2229][Zjoi2011]最小割

来自FallDream的博客,未经允许,请勿转载,谢谢。


小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。 对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割” 现给定一张无向图,小白有若干个形如“图中有多少对点它们的最小割的容量不超过x呢”的疑问,小蓝虽然很想回答这些问题,但小蓝最近忙着挖木块,于是作为仍然是小蓝的好友,你又有任务了。

T<=10,n<=150,m<=3000,q<=30

最小割树(分治+最小割)

每次从要分治的部分中选出两个点求最小割,并且更新与S相连的部分的点和与T相连的部分的点的答案,然后切成两半分别分治下去即可。

总共分治n次

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define MN 150
#define INF 2000000000
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
vector<int> v[MN*MN+5];
bool in[MN+5];
int n,m,head[MN+5],cnt=1,tot=0,d[MN+5],q[MN+5],top,c[MN+5],Ans[MN+5][MN+5],bel[MN+5],S,T;
struct edge{int to,next,w,tot;}e[30005];
inline void ins(int f,int t,int w)
{
    e[++cnt]=(edge){t,head[f],w,w};head[f]=cnt;
    e[++cnt]=(edge){f,head[t],0,0};head[t]=cnt;
}

void rebuild(){for(int i=2;i<=cnt;++i)e[i].w=e[i].tot;}

void Dfs(int x)
{
    v[bel[x]=tot].push_back(x);
    for(int i=head[x];i;i=e[i].next)
        if(!bel[e[i].to]) Dfs(e[i].to);
}

int dfs(int x,int f)
{
    if(x==T) return f;
    int used=0;
    for(int&i=c[x];i;i=e[i].next)
        if(e[i].w&&d[e[i].to]==d[x]+1)
        {
            int w=dfs(e[i].to,min(f-used,e[i].w));
            used+=w;e[i].w-=w;e[i^1].w+=w;
            if(used==f) return used;
        }
    return d[x]=-1,used;
}

bool bfs()
{
    memset(d,0,sizeof(d));int i,j;
    for(d[q[top=i=1]=S]=1;i<=top;++i)
        for(j=c[q[i]]=head[q[i]];j;j=e[j].next)
            if(e[j].w&&!d[e[j].to]) d[q[++top]=e[j].to]=d[q[i]]+1;
    return d[T];
}

void Get(int x)
{
    in[x]=1;
    for(int i=head[x];i;i=e[i].next)
        if(!in[e[i].to]&&e[i].w) Get(e[i].to);
}

void Solve(int now)
{
    if(v[now].size()<2) {v[now].clear();return;}
    S=v[now][0],T=v[now][1];rebuild();int ans=0;
    while(bfs()) ans+=dfs(S,INF);
    memset(in,0,sizeof(in));Get(S);
    for(int i=1;i<=n;++i)
        for(int j=i+1;j<=n;++j)
            if(in[i]^in[j]) Ans[i][j]=min(Ans[i][j],ans);
    for(int i=1;i<=n;++i)
        if(bel[i]==now)
            bel[i]=(in[i]?tot+1:tot+2),v[bel[i]].push_back(i);
    int pre=tot;tot+=2;Solve(pre+1);Solve(pre+2);
    v[now].clear();
}

int main()
{
    for(int cas=read();cas;--cas)
    {
        n=read();m=read();cnt=1;tot=0;
        memset(head,0,sizeof(head));
        memset(bel,0,sizeof(bel));
        memset(Ans,127,sizeof(Ans));
        for(int i=1;i<=m;++i)
        {
            int x=read(),y=read(),w=read();
            ins(x,y,w);ins(y,x,w);
        }
        for(int i=1;i<=n;++i)
            if(!bel[i]) ++tot,Dfs(i),Solve(tot);
        for(int i=1;i<=n;++i)
            for(int j=i+1;j<=n;++j)
                Ans[i][j]>INF?Ans[i][j]=0:0;
        for(int q=read();q;--q)
        {
            int num=read(),ans=0;
            for(int i=1;i<n;++i)
                for(int j=i+1;j<=n;++j)
                    if(Ans[i][j]<=num) ++ans;
            printf("%d
",ans);    
        }
        puts("");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/FallDream/p/bzoj2229.html