• 【BZOJ1797】最小割(AHOI2009)-最小割+SCC


    测试地址:最小割
    做法:本题需要用到最小割+SCC。
    首先,根据最大流和最小割的关系不难看出,跑完最大流后没有满流的边都不可能出现在最小割中。
    那么对于剩下的边,如果它的两个端点在残余网络中(注意,残余网络是带反向边的)在同一个强连通分量内,很显然它也不可能出现在最小割中(因为割掉这条边没什么意义),否则它就可能出现在最小割中。
    而对于一条边,如果它的两个端点在残余网络中分别和源点和汇点在同一个强连通分量中,那么它就一定出现在最小割中,因为一旦它容量变大,我们就可以增广出新的最大流,矛盾。
    得出上述的结论之后,我们就可以按照上面的条件判定每条边属于哪种情况了。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll inf=(ll)1000000000*(ll)1000000000;
    int n,m,S,T,first[4010]={0},tot=1;
    int lvl[4010],cur[4010],h,t,q[4010];
    int st[4010],belong[4010],top=0,totscc=0,dfn[4010],low[4010],tim=0;
    bool vis[4010]={0},inst[4010]={0};
    struct edge
    {
        int v,next;
        ll f;
    }e[120010];
    
    void insert(int a,int b,ll f)
    {
        e[++tot].v=b,e[tot].next=first[a],e[tot].f=f,first[a]=tot;
        e[++tot].v=a,e[tot].next=first[b],e[tot].f=0,first[b]=tot;
    }
    
    bool makelevel()
    {
        for(int i=1;i<=n;i++)
            lvl[i]=-1,cur[i]=first[i];
        h=t=1;
        q[1]=S;
        lvl[S]=0;
        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)
    {
        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));
                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;
    }
    
    void dinic()
    {
        while(makelevel()) maxflow(S,inf);
    }
    
    void tarjan(int v)
    {
        vis[v]=inst[v]=1;
        st[++top]=v;
        dfn[v]=low[v]=++tim;
        int now=top;
        for(int i=first[v];i;i=e[i].next)
            if (e[i].f)
            {
                if (!vis[e[i].v])
                {
                    tarjan(e[i].v);
                    low[v]=min(low[v],low[e[i].v]);
                }
                else if (inst[e[i].v]) low[v]=min(low[v],dfn[e[i].v]);
            }
        if (dfn[v]==low[v])
        {
            totscc++;
            for(int i=now;i<=top;i++)
            {
                belong[st[i]]=totscc;
                inst[st[i]]=0;
            }
            top=now-1;
        }
    }
    
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&S,&T);
        for(int i=1;i<=m;i++)
        {
            int a,b;
            ll c;
            scanf("%d%d%lld",&a,&b,&c);
            insert(a,b,c);
        }
    
        dinic();
        for(int i=1;i<=n;i++)
            if (!vis[i]) tarjan(i);
        for(int i=1;i<=m;i++)
        {
            if (e[i<<1].f) {printf("0 0
    ");continue;}
            if (belong[e[i<<1].v]!=belong[e[i<<1|1].v]) printf("1 ");
            else {printf("0 0
    ");continue;}
            if (belong[e[i<<1].v]==belong[T]&&belong[e[i<<1|1].v]==belong[S])
                printf("1
    ");
            else printf("0
    ");
        }
    
        return 0;
    }
  • 相关阅读:
    PHP 进制汉字转化
    当调用方法没有注释信息并且参数不全
    DBCP数据库连接池技术的两种实现方式
    汇编语言中一步执行循环
    求最小函数依赖集
    汇编语言实验四
    汇编语言第七章
    batch实现数据库的批量插入Unknown system variable 'query_cache_size'
    汇编语言第一节课:数制转换,真值和补码
    Forsaken喜欢数论
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793436.html
Copyright © 2020-2023  润新知