[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;
}
慢即是快,细则是能,于小处铸迤逦
原文地址:https://www.cnblogs.com/Hale522520/p/10642073.html