zoukankan      html  css  js  c++  java
  • 【BZOJ2095】Bridges(POI2010)-欧拉回路+二分+最大流

    测试地址:Bridges
    做法:本题需要用到欧拉回路+二分+最大流。
    首先回顾欧拉回路的定义:经过图中一条边一次且仅一次的回路。那么如果原图不是欧拉图(即存在度数为奇数的点),则显然不存在这样的回路,否则因为要求最大值最小,我们二分最大的边权x,将问题转化为判定性问题。
    那么我们现在就要判定,如果只能走风力不超过x的边,能不能走出一条欧拉回路。我们知道要走成一个欧拉回路,就是给每条边选一个走的方向,使得每个点入度和出度相等,即入度为它在原图中度数的一半。因为一条边只能提供一个点入度,而一个点可以从多条边获得入度,我们显然可以这样建图:从源点向每条边连容量为1的边,从每条边向它的端点连容量为1的边,从每个点向汇点连容量为它的度数的一半的边,显然每一份流量都代表我们完成了一条边到一个点的匹配,那么我们求出最大流后,判断最大流是不是等于m即可。这样我们就完成了这一题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int inf=1000000000;
    int n,m,S,T,deg[3010],first[3010],tot;
    int a[3010],b[3010],c[3010],d[3010];
    int h,t,q[3010],lvl[3010],cur[3010];
    struct edge
    {
        int v,next,f;
    }e[20010];
    
    void insert(int a,int b,int f)
    {
        e[++tot].v=b,e[tot].next=first[a],e[tot].f=f,first[a]=tot;
        e[++tot].v=a,e[tot].next=first[b],e[tot].f=0,first[b]=tot;
    }
    
    bool makelevel()
    {
        for(int i=1;i<=T;i++)
            lvl[i]=-1,cur[i]=first[i];
        h=t=1;
        q[1]=S;
        lvl[S]=0;
        while(h<=t)
        {
            int v=q[h++];
            for(int i=first[v];i;i=e[i].next)
                if (e[i].f&&lvl[e[i].v]==-1)
                {
                    lvl[e[i].v]=lvl[v]+1;
                    q[++t]=e[i].v;
                }
        }
        return lvl[T]!=-1;
    }
    
    int maxflow(int v,int maxf)
    {
        int ret=0,f;
        if (v==T) return maxf;
        for(int i=cur[v];i;i=e[i].next)
        {
            if (e[i].f&&lvl[e[i].v]==lvl[v]+1)
            {
                f=maxflow(e[i].v,min(maxf-ret,e[i].f));
                ret+=f;
                e[i].f-=f;
                e[i^1].f+=f;
                if (ret==maxf) break;
            }
            cur[v]=i;
        }
        if (!ret) lvl[v]=-1;
        return ret;
    }
    
    bool check(int mid)
    {
        memset(first,0,sizeof(first));
        tot=1;
        for(int i=1;i<=m;i++)
        {
            insert(S,i,1);
            if (c[i]<=mid) insert(i,m+b[i],1);
            if (d[i]<=mid) insert(i,m+a[i],1);
        }
        for(int i=1;i<=n;i++)
            insert(m+i,T,deg[i]>>1);
        int maxf=0;
        while(makelevel())
            maxf+=maxflow(S,inf);
        return maxf==m;
    }
    
    int main()
    {
        int l=inf,r=0;
    
        scanf("%d%d",&n,&m);
        S=n+m+1,T=n+m+2;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
            l=min(l,c[i]),l=min(l,d[i]);
            r=max(r,c[i]),r=max(r,d[i]);
            deg[a[i]]++,deg[b[i]]++;
        }
    
        for(int i=1;i<=n;i++)
            if (deg[i]%2) {printf("NIE");return 0;}
    
        while(r>l)
        {
            int mid=(l+r)>>1;
            if (check(mid)) r=mid;
            else l=mid+1;
        }
        printf("%d",l);
    
        return 0;
    }
  • 相关阅读:
    HTML元素解释
    Java命名规范
    HDU 1058 Humble Numbers(DP,数)
    HDU 2845 Beans(DP,最大不连续和)
    HDU 2830 Matrix Swapping II (DP,最大全1矩阵)
    HDU 2870 Largest Submatrix(DP)
    HDU 1421 搬寝室(DP)
    HDU 2844 Coins (组合背包)
    HDU 2577 How to Type(模拟)
    HDU 2159 FATE(二维完全背包)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793433.html
Copyright © 2011-2022 走看看