• [bzoj1797][Ahoi2009]Mincut 最小割


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


    A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路。设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci。现在B国想找出一个路径切断方案,使中转站s不能到达中转站t,并且切断路径的代价之和最小。  小可可一眼就看出,这是一个求最小割的问题。但爱思考的小可可并不局限于此。现在他对每条单向道路提出两个问题:   问题一:是否存在一个最小代价路径切断方案,其中该道路被切断?  问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断?   现在请你回答这两个问题。

    n<=4000 m<=60000

    题解:先跑一次最小割,然后在残量网络上tarjan,用所有没满流的边缩点。

    由于是最小割,所以显然ST不在同一块

    一条边如果没有满流,那么它就不可能被割了。在这基础上:

      一条边可以被割当且仅当连接的两个点所属的块不同。

      一条边一定被割当且仅当连接的两个点分别和S,T同块。

    证明我不会,转一个鏼爷(jcvb)的题解:

    <==将每个SCC缩成一个点,得到的新图就只含有满流边了。那么新图的任一s-t割都对应原图的某个最小割,从中任取一个把id[u]和id[v]割开的割即可证明。

     < ==:假设将(u,v)的边权增大,那么残余网络中会出现s->u->v->t的通路,从而能继续增广,于是最大流流量(也就是最小割容量)会增大。这即说明(u,v)是最小割集中必须出现的边。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define MN 4000
    #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;
    }
    
    int n,m,S,T,head[MN+5],cnt=1,d[MN+5],c[MN+5],q[MN+5],top,dn=0,dfn[MN+5],low[MN+5],bel[MN+5],cc=0;
    struct edge{int from,to,next,w;}e[120005];
    
    inline void ins(int f,int t,int w)
    {
        e[++cnt]=(edge){f,t,head[f],w};head[f]=cnt;
        e[++cnt]=(edge){t,f,head[t],0};head[t]=cnt;
    }
    
    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 tarjan(int x)
    {
        dfn[x]=low[x]=++dn;q[++top]=x;
        for(int i=head[x];i;i=e[i].next)
            if(e[i].w)
            {
                if(!dfn[e[i].to]) 
                    tarjan(e[i].to),low[x]=min(low[x],low[e[i].to]);
                else
                    if(!bel[e[i].to]) low[x]=min(low[x],dfn[e[i].to]); 
            }
        if(dfn[x]==low[x])
            for(++cc;q[top+1]!=x;--top)
                bel[q[top]]=cc;
    }
    
    int main()
    {
        n=read();m=read();S=read();T=read();
        for(int i=1;i<=m;i++)
        {
            int u=read(),v=read(),c=read();
            ins(u,v,c);
        }
        while(bfs()) dfs(S,INF); top=0;
        memset(q,0,sizeof(q));
        for(int i=1;i<=n;i++)
            if(!dfn[i]) tarjan(i);
        for(int i=2;i<=cnt;i+=2)
            printf("%d %d
    ",!e[i].w&&bel[e[i].from]!=bel[e[i].to],bel[e[i].from]==bel[S]&&bel[e[i].to]==bel[T]);
        return 0;
    }
  • 相关阅读:
    LeetCode 150:逆波兰表达式求值 Evaluate Reverse Polish Notation
    LeetCode 20:有效的括号 Valid Parentheses
    LeetCode 155:最小栈 Min Stack
    rsync & sersync 实时同步
    rsync & inotify-tools 实时同步
    rsync 应用总结
    Linux 变量详解
    特殊权限
    Linux 三剑客之sed命令总结
    expect 分发ssh key脚本
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj1797.html
Copyright © 2020-2023  润新知