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;
        }
    }
    
    
    嗯,就这样了...
  • 相关阅读:
    C#中的编译为什么不叫Compile而叫build
    类型(Type)
    C#中关于值类型和引用类型的区别
    php通用化api格式输出
    tp6获取参数的五种办法
    PHP 数组------分割、合并
    explain结果中的type字段的含义
    order by 排序
    SQL开发技巧
    tp5模板输出日期时间
  • 原文地址:https://www.cnblogs.com/yzhx/p/14616916.html
Copyright © 2011-2022 走看看