zoukankan      html  css  js  c++  java
  • 【BZOJ2229】最小割(ZJOI2011)-分治+最小割(最小割树)

    测试地址:最小割
    做法:本题需要用到分治+最小割。
    暴力算最小割需要算n(n1)2次最小割,难以接受,这时候就要掏出最小割树这个东西了。
    最小割树是一种可以描述所有点对间最小割的结构,构造过程如下:
    1.在点集中任选两点x,y,求出它们间的最小割s
    2.在最小割树中连接边(x,y),边权为s
    3.求出的割边将点集分为两个集合ST,递归处理ST
    大概就是这样一个过程,这个过程中只求了n1次最小割,得到了优化。
    最小割树的一个性质是:任意两点间的最小割,等于它们在最小割树上路径上的最小边权。具体我不怎么会证,感性理解一下吧……总之按照上面方法把最小割树建出来,再在上面简单处理询问即可。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll inf=(ll)1000000000*(ll)1000000000;
    int Test,n,m,qr,first[210],tot,p[210],S[210],T[210];
    int firsted[210],toted,ans;
    int h,t,q[210],lvl[210],cur[210];
    ll nowx;
    bool vis[210];
    struct edge
    {
        int v,next;
        ll used,f;
    }e[10010],ed[10010];
    
    void insert(int a,int b,ll f)
    {
        e[++tot].v=b,e[tot].next=first[a],e[tot].used=f,first[a]=tot;
        e[++tot].v=a,e[tot].next=first[b],e[tot].used=f,first[b]=tot;
    }
    
    void inserted(int a,int b,ll f)
    {
        ed[++toted].v=b,ed[toted].next=firsted[a],ed[toted].f=f,firsted[a]=toted;
        ed[++toted].v=a,ed[toted].next=firsted[b],ed[toted].f=f,firsted[b]=toted;
    }
    
    bool makelevel(int S,int T)
    {
        for(int i=1;i<=n;i++)
            lvl[i]=-1,cur[i]=first[i];
        lvl[S]=0;
        h=t=1;
        q[1]=S;
        while(h<=t)
        {
            int v=q[h++];
            for(int i=first[v];i;i=e[i].next)
                if (e[i].f&&lvl[e[i].v]==-1)
                {
                    lvl[e[i].v]=lvl[v]+1;
                    q[++t]=e[i].v;
                }
        }
        return lvl[T]!=-1;
    }
    
    ll maxflow(int v,ll maxf,int T)
    {
        ll ret=0,f;
        if (v==T) return maxf;
        for(int i=cur[v];i;i=e[i].next)
        {
            if (e[i].f&&lvl[e[i].v]==lvl[v]+1)
            {
                f=maxflow(e[i].v,min(maxf-ret,e[i].f),T);
                ret+=f;
                e[i].f-=f;
                e[i^1].f+=f;
                if (ret==maxf) break;
            }
            cur[v]=i;
        }
        if (!ret) lvl[v]=-1;
        return ret;
    }
    
    ll dinic(int S,int T)
    {
        ll maxf=0;
        for(int i=2;i<=(m<<1)+1;i++)
            e[i].f=e[i].used;
        while(makelevel(S,T))
            maxf+=maxflow(S,inf,T);
        return maxf;
    }
    
    void findS(int v)
    {
        vis[v]=1;
        for(int i=first[v];i;i=e[i].next)
            if (e[i].f&&!vis[e[i].v]) findS(e[i].v);
    }
    
    void solve(int l,int r)
    {
        if (l==r) return;
        int s=dinic(p[l],p[r]);
        inserted(p[l],p[r],s);
    
        memset(vis,0,sizeof(vis));
        findS(p[l]);
        S[0]=T[0]=0;
        for(int i=l;i<=r;i++)
        {
            if (vis[p[i]]) S[++S[0]]=p[i];
            else T[++T[0]]=p[i];
        }
        for(int i=1;i<=S[0];i++)
            p[l+i-1]=S[i];
        for(int i=1;i<=T[0];i++)
            p[l+S[0]+i-1]=T[i];
    
        int sizS=S[0];
        solve(l,l+sizS-1);
        solve(l+sizS,r);
    }
    
    void dfs(int v,int fa,ll mn)
    {
        if (mn<=nowx) ans++;
        for(int i=firsted[v];i;i=ed[i].next)
            if (ed[i].v!=fa) dfs(ed[i].v,v,min(mn,ed[i].f));
    }
    
    int main()
    {
        scanf("%d",&Test);
        while(Test--)
        {
            memset(first,0,sizeof(first));
            tot=1;
    
            scanf("%d%d",&n,&m);
            for(int i=1;i<=m;i++)
            {
                int u,v;
                ll c;
                scanf("%d%d%lld",&u,&v,&c);
                insert(u,v,c);
            }
    
            memset(firsted,0,sizeof(firsted));
            toted=0;
            tot=0;
            for(int i=1;i<=n;i++)
                p[i]=i;
            solve(1,n);
    
            scanf("%d",&qr);
            for(int i=1;i<=qr;i++)
            {
                scanf("%lld",&nowx);
                ans=0;
                for(int j=1;j<=n;j++)
                    dfs(j,0,inf);
                printf("%d
    ",ans>>1);
            }
            printf("
    ");
        }
    
        return 0;
    }
  • 相关阅读:
    LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)
    LeetCode 216. 组合总和 III(Combination Sum III)
    LeetCode 179. 最大数(Largest Number)
    LeetCode 199. 二叉树的右视图(Binary Tree Right Side View)
    LeetCode 114. 二叉树展开为链表(Flatten Binary Tree to Linked List)
    LeetCode 106. 从中序与后序遍历序列构造二叉树(Construct Binary Tree from Inorder and Postorder Traversal)
    指针变量、普通变量、内存和地址的全面对比
    MiZ702学习笔记8——让MiZ702变身PC的方法
    你可能不知道的,定义,声明,初始化
    原创zynq文章整理(MiZ702教程+例程)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793438.html
Copyright © 2011-2022 走看看