[AHOI2009]最小割

大概意思是让求一个图的最小割的必须边和可行边

然后做法就是在残量网络上跑tarjan缩点。如果这个边没有满流,它就没有被割,肯定不是。

如果这个边的from和to不在一个点,就是可行边。如果from和S在一起,to和T在一起,就是必须边。

jcvb:(策神Orz

在残余网络上跑tarjan求出所有SCC,记id[u]为点u所在SCC的编号。显然有id[s]!=id[t](否则s到t有通路,能继续增广)。

①对于任意一条满流边(u,v),(u,v)能够出现在某个最小割集中,当且仅当id[u]!=id[v];
②对于任意一条满流边(u,v),(u,v)必定出现在最小割集中,当且仅当id[u]==id[s]且id[v]==id[t]。

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
int n,m,S,T,ecnt=1;
const int M=120005,N=40005;
struct Edge{
    int from,to,nxt,val;
}e[M];
int h[N],maxflow,head[N];
inline void add(int bg,int ed,int val) {
    e[++ecnt]=(Edge){bg,ed,head[bg],val};head[bg]=ecnt;
}
bool bfs() {
    queue<int>q;
    q.push(S);
    memset(h,-1,sizeof (int)*(n+4));
    h[S]=0;
    while(!q.empty()) {
        int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].nxt) {
            int v=e[i].to;
            if(h[v]==-1&&e[i].val) {
                h[v]=h[u]+1;q.push(v);
            }
        }
    }
    return h[T]!=-1;
}
int dfs(int x,int f) {
    if(x==T) return f;
    int used=0,tp;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].to;
        if(e[i].val&&h[x]+1==h[v]) {
            tp=dfs(v,min(e[i].val,f-used));
            used+=tp;
            e[i].val-=tp;
            e[i^1].val+=tp;
            if(used==f) return used;
        }
    }
    if(used==0) h[x]=-1;
    return used;
}
void dinic() {while(bfs())dfs(S,0x3f3f3f3f);}
int stk[N],top,id[N],low[N],dfn[N],tim,tot;
bool vis[N];
void tarjan(int x) {
    low[x]=dfn[x]=++tim;vis[x]=1;stk[++top]=x;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].to;
        if(!e[i].val) continue;
        if(!dfn[v]) {
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(vis[v]) low[x]=min(low[x],dfn[v]);
    }
    if(dfn[x]==low[x]) {
        id[x]=++tot;vis[x]=0;
        while(stk[top]!=x) {
            id[stk[top]]=tot;vis[stk[top]]=0;
            top--;
        }
        top--;
    }
}
int main() {
    scanf("%d%d%d%d",&n,&m,&S,&T);
    for(int i=1,a,b,c;i<=m;i++) scanf("%d%d%d",&a,&b,&c),add(a,b,c),add(b,a,0);
    dinic();
    for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
    for(int i=2;i<=ecnt;i+=2) {
        if(e[i].val) {puts("0 0");continue;}
        if(id[e[i].from]!=id[e[i].to])
            putchar('1');
        else {puts("0 0");continue;}
        putchar(' ');
        if(id[S]==id[e[i].from]&&id[T]==id[e[i].to]) puts("1");else puts("0");
        
    }
}
最小割
我是咸鱼。转载博客请征得博主同意Orz
原文地址:https://www.cnblogs.com/sdfzhsz/p/9732124.html