zoukankan      html  css  js  c++  java
  • BZOJ_1797_[Ahoi2009]Mincut 最小割_最小割+tarjan

    BZOJ_1797_[Ahoi2009]Mincut 最小割_最小割+tarjan

    Description

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

    Sample Input

    6 7 1 6
    1 2 3
    1 3 2
    2 4 4
    2 5 1
    3 5 5
    4 6 2
    5 6 3

    Sample Output

    1 0
    1 0
    0 0
    1 0
    0 0
    1 0
    1 0


    首先求一遍最小割,然后在残量网络缩点。显然有S,T不在同一强连通分量中。

    考虑边(u,v) ,如果u和v在同一scc中,那么割去这条边后仍有通路,因此它不会出现在任何一边的割集当中。

    如果S和u在同一scc并且v和T在同一scc,那么假设在这条边上多加一些流量,那么从S到T则又可以增广,因此它一定会被割掉。

    如果这条边没有满流,它同样不会被割掉。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 5000
    #define M 120050
    #define inf 100000000
    #define mem(x) memset(x,0,sizeof(x));
    int head[N],to[M],nxt[M],flow[M],n,m,cnt=1;
    int dep[N],Q[N],l,r,S,T;
    int St[N],top,ins[N],bl[N],scc,tot,dfn[N],low[N];
    inline void add(int u,int v,int f){
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;flow[cnt]=f;
    }
    bool bfs(){
        l=r=0;
        mem(dep);
        Q[r++]=S;dep[S]=1;
        while(l<r){
            int x=Q[l++];
            for(int i=head[x];i;i=nxt[i]){
                if(!dep[to[i]]&&flow[i]){
                    dep[to[i]]=dep[x]+1;
                    if(to[i]==T)return 1;
                    Q[r++]=to[i];
                }
            }
        }return 0;
    }
    int dfs(int x,int mf){
        if(x==T)return mf;
        int nf=0;
        for(int i=head[x];i;i=nxt[i]){
            if(dep[to[i]]==dep[x]+1&&flow[i]){
                int tmp=dfs(to[i],min(mf-nf,flow[i]));
                nf+=tmp;
                flow[i]-=tmp;
                flow[i^1]+=tmp;
                if(nf==mf)break;
            }
        }
        dep[x]=0;return nf;
    }
    void dinic(){
        int ans=0,f=0;
        while(bfs()){
            while(f=dfs(S,inf)){
                ans+=f;
            }
        }
    }
    void tarjan(int x){
        dfn[x]=low[x]=++tot;
        St[top++]=x;ins[x]=1;
        for(int i=head[x];i;i=nxt[i]){
            if(flow[i]==0)continue;
            if(!dfn[to[i]]){
                tarjan(to[i]);
                low[x]=min(low[x],low[to[i]]);
            }else if(!bl[to[i]]){
                low[x]=min(low[x],dfn[to[i]]);
            }
        }
        if(low[x]==dfn[x]){
            int t=St[--top];ins[t]=0;
            bl[t]=++scc;
            while(t^x){
                t=St[--top];ins[t]=0;
                bl[t]=scc;
            }
        }
    }
    int main(){
        scanf("%d%d%d%d",&n,&m,&S,&T);
        int x,y,z;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);add(y,x,0);
        }
        dinic();
        for(int i=1;i<=n;i++){
            if(!dfn[i])tarjan(i);
        }
        for(int i=1;i<=m;i++){
            if(flow[i<<1]){
                printf("0 0
    ");continue;
            }   
            int g=to[i<<1|1],h=to[i<<1];
            printf("%d %d
    ",bl[g]!=bl[h],bl[g]==bl[S]&&bl[h]==bl[T]);
            /*if(bl[g]!=bl[h])printf("1");
            else printf("0");
            if(bl[g]==bl[S]&&bl[h]==bl[T])printf(" 1
    ");
            else printf(" 0
    ");*/
        }
    }
    
  • 相关阅读:
    Anderson《空气动力学基础》5th读书笔记 第0记——白金汉PI定理
    108、将有序数组转换为二叉搜索树
    104、二叉树的最大深度
    237、删除链表中的节点
    1480、一维数组的动态和
    伪类与伪元素的由来及区别
    617、合并二叉树
    CDN
    JS DOM编程艺术 | 笔记
    HTML进阶
  • 原文地址:https://www.cnblogs.com/suika/p/9078636.html
Copyright © 2011-2022 走看看