zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    Linux学习篇(四):学习 gdb
    Linux学习篇(三):学习 gcc
    c#序列化感悟(重点讲讲二进制序列化)
    参数保存随笔
    写程序时try,catch查看报错的行号
    stram流char[]保存,支持中文,Filestram需要先转byte[]才能使用,但是性能更好《转载》
    c#序列化和反序列化《转载》
    如果两个测量设备出现相关性数据问题,且过度像素没区别?(打光效果一致),怎么办
    当Hobject类型出现内存泄漏爆炸增长的问题,怎么处理
    使用gige2500万相机时遇见的问题(条纹以及取图过久)
  • 原文地址:https://www.cnblogs.com/sdfzhsz/p/9732124.html
Copyright © 2011-2022 走看看