zoukankan      html  css  js  c++  java
  • [AHOI2009]最小割

    题意

    给定一个带权有向图,对每条边回答:
    是否可能出现在最小割中,是否必定出现在最小割中
    n<=4000,m<=60000

    Solution

    根据网络流最大流的性质,可得出结论:

    对于最小割中两种边:

    可行边:
    1.必定满流
    2.残量网络中两端不连通

    必经边:
    1.一定是可行边(有可行边的两条性质)
    2.残量网络中两端分别联通S,T

    可以先缩点,然后再用并查集判断

    code

    #include<bits/stdc++.h>
    using namespace std;
    #define re register
    #define ll long long
    #define get getchar()
    #define in inline
    in int read()
    {
        int t=0; char ch=get;
        while(ch<'0' || ch>'9') ch=get;
        while(ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
        return t;
    }
    const int _=6010;
    const int inf=0x3f3f3f3f;
    int n,m,S,T,tot=1, h[_];
    struct edge{
        int to,ne,w,fr;
    }e[500010];
    in void add(int x,int y,int z)
    {
        e[++tot].ne=h[x], e[tot].to=y, e[tot].w=z, h[x]=tot, e[tot].fr=x;
        e[++tot].ne=h[y], e[tot].to=x, e[tot].w=0, h[y]=tot, e[tot].fr=y; 
    }
    int dis[_],cur[_];
    in int dfs(int u,int flow)
    {
        if(!flow || u==T) return flow;
        int used=0,d;
        for(re int i=cur[u];i;i=e[i].ne)
        {
            int v=e[i].to; cur[u]=i;
            if(e[i].w && dis[v]==dis[u]+1)
                if(d=dfs(v,min(flow-used,e[i].w)))
                {
                    e[i].w-=d, e[i^1].w+=d, used+=d;
                    if(used==flow) break;
                }
        }
        return used;
    }
    in int bfs()
    {
        queue<int> q;
        memset(dis,0x3f,sizeof(dis));
        dis[S]=0; q.push(S);
        while(!q.empty())
        {
            int u=q.front(); q.pop();
            cur[u]=h[u];
            for(re int i=h[u],v=e[i].to; i; i=e[i].ne, v=e[i].to)
                if(e[i].w && dis[v]==inf) dis[v]=dis[u]+1, q.push(v);
        }
        return dis[T]!=inf;
    }
    int ans;
    in void dinic()
    {   int t; while(bfs())while(t=dfs(S,inf))ans+=t; }
    int dfn[_], low[_], vis[_], st[_], top, cnt, num,col[_];
    in void tarjan(int u)
    {
        dfn[u]=low[u]=++cnt;st[++top]=u; vis[u]=1;
        for(re int i=h[u];i;i=e[i].ne)
        {
            int v=e[i].to;
            if(!e[i].w) continue;
            if(!dfn[v]) {
                tarjan(v);
                low[u]=min(low[u], low[v]);
            }
            else if(vis[v]) low[u]=min(low[u], dfn[v]);
        }
        if(dfn[u]!=low[u]) return;
        ++num;
        while(top)
        {
            int x=st[top--];
            col[x]=num, vis[x]=0;
            if(x==u) break;
        }
    }
    int a[_][2];
    in void work(int x,int id)
    {
        queue<int> q; q.push(x); a[x][id]=1;
        while(!q.empty())
        {
            int u=q.front(); q.pop();
            for(re int i=h[u];i;i=e[i].ne)
            {
                int v=e[i].to;
                if(!e[i^id].w || a[v][id]) continue;
                a[v][id]=1; q.push(v);
            }
        }
    }
    int main()
    {
        n=read(), m=read(), S=read(), T=read();
        for(re int i=1;i<=m;i++)
        {
            int x=read(), y=read(), z=read();
            add(x,y,z);
        }
        dinic();
        for(re int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
        work(S,0), work(T,1);
        for(re int i=2;i<=1+2*m;i+=2)
        {
            int x=e[i].fr, y=e[i].to;
            if(!e[i].w&&col[x]!=col[y]) cout<<"1 ";
            else cout<<"0 ";
            if(a[x][0]&a[y][1]) cout<<"1
    ";
            else cout<<0<<endl;
        }
    }
    
    
    嗯,就这样了...
  • 相关阅读:
    Codeforces 992C(数学)
    Codeforces 990C (思维)
    Codeforces 989C (构造)
    POJ 1511 Invitation Cards(链式前向星,dij,反向建边)
    Codeforces 1335E2 Three Blocks Palindrome (hard version)(暴力)
    POJ 3273 Monthly Expense(二分)
    POJ 2566 Bound Found(尺取前缀和)
    POJ 1321 棋盘问题(dfs)
    HDU 1506 Largest Rectangle in a Histogram(单调栈)
    POJ 2823 Sliding Window(单调队列)
  • 原文地址:https://www.cnblogs.com/yzhx/p/14616916.html
Copyright © 2011-2022 走看看