• [AHOI2009]最小割(最大流+tarjan)


    继续填坑了,啦啦啦

    这道题本来是准备枚举每个边,暂时去除它,但发现时间会爆炸的

    于是决定另辟蹊径

    于是这篇题解就应运而生

    首先还是网络流跑一边 毕竟题目叫最小割嘛,给个面子

    然后跑一边tarjan对满流的边处理掉,即不相连

    之后对每条边进行判断,如果当前的边流量为0并且始末点不在一个集合,那么就满足第一个条件了

    若始末点于源点汇点为同一个集合,那么就满足第二个条件了

    不然的话直接输出0 0 即可

    题面

    #include<bits/stdc++.h>
    using namespace std;
    const int N=4e5+7;
    const int INF=0x7f7f7f;
    int m,n,k,s,t,cnt=1,mx,ans,idx;
    int dep[N],head[N],dfn[N],low[N],color[N],sum[N],num;
    bool vis[N];
    stack<int> st;
    struct edge
    {
        int nx,to,flow,from;
    } e[N];
    void add_edge(int a,int b,int flow)
    {
        cnt++;e[cnt].flow=flow;e[cnt].nx=head[a];e[cnt].to=b;e[cnt].from=a;head[a]=cnt;
        cnt++;e[cnt].flow=0;e[cnt].nx=head[b];e[cnt].to=a;e[cnt].from=b;head[b]=cnt;
    }
    bool bfs(int s,int t)
    {
        memset(dep,0,sizeof(dep));queue<int> que;
        dep[s]=1;que.push(s);
        while (!que.empty())
        {
            int x=que.front();que.pop();
            for (int i=head[x];i;i=e[i].nx)
            {
                int y=e[i].to;
                if (dep[y]==0&&e[i].flow)
                {
                    dep[y]=dep[x]+1;
                    que.push(y);
                }
            }
        }
        if (dep[t]==0) return false;
        else return true;
    }
    void paint(int x)
    {
        st.pop();
        color[x]=num;
        sum[num]++;
        vis[x]=false;
    }
    void tarjan(int x)
    {
        dfn[x]=low[x]=++idx;
        st.push(x);vis[x]=true;
        for (int i=head[x];i;i=e[i].nx)
        {
            if (e[i].flow==0) continue;
            int y=e[i].to;
            if (!dfn[y])
            {
                tarjan(y);
                low[x]=min(low[x],low[y]);
            }
            else if (vis[y]) low[x]=min(low[x],dfn[y]);
        }
        if (dfn[x]==low[x])
        {
            num++;
            while (st.top()!=x)
            {
                int t=st.top();
                paint(t);
            }
            paint(x);
        }
    }
    int dfs(int x,int limit,int t)
    {
        if (x==t) return limit;
        int used=0;
        for (int i=head[x];i;i=e[i].nx)
        {
            int y=e[i].to;
            if (dep[y]==dep[x]+1&&e[i].flow)
            {
                int di=dfs(y,min(limit-used,e[i].flow),t);
                if (di>0)
                {
                    e[i].flow-=di;
                    e[i^1].flow+=di;
                    used+=di;
                    if (used==limit) return limit;
                }
            }
        }
        if (!used) dep[x]=-2;
        return used;
    }
    void dinic(int s,int t)
    {
        while (bfs(s,t)) ans+=dfs(s,INF,t);
    }
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for (int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add_edge(x,y,z);
        }
        dinic(s,t);
        mx=ans;
        for (int i=1;i<=n;i++)
        if (!color[i]) tarjan(i);
        for (int i=2;i<cnt;i+=2)
        {
            int x=e[i].from,y=e[i].to;
            if (color[x]!=color[y]&&e[i].flow==0)
            {
                printf("1 ");
                if (color[x]==color[s]&&color[y]==color[t]) printf("1");
                else printf("0");
            }
            else printf("0 0");
            printf("
    "); 
        }
        return 0;
    }
    慢即是快,细则是能,于小处铸迤逦
  • 相关阅读:
    java 多线程面试题
    finally语句块一定会被执行吗
    redis 数据结构
    哪些可以作为GC ROOT
    mybatis 源码分析--日志分析
    mybatis selectKey
    spring cache 和redis
    kafka是如何保证消息不被重复消费的
    kafka面试题及答案
    浅谈:2019 前端面试题
  • 原文地址:https://www.cnblogs.com/Hale522520/p/10642073.html
Copyright © 2020-2023  润新知