zoukankan      html  css  js  c++  java
  • 【BZOJ-2095】Bridge 最大流 + 混合图欧拉回路 + 二分

    2095: [Poi2010]Bridges

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 604  Solved: 218
    [Submit][Status][Discuss]

    Description

    YYD为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个小岛可以到另外任意一个小岛。现在YYD想骑单车从小岛1出发,骑过每一座桥,到达每一个小岛,然后回到小岛1。霸中同学为了让YYD减肥成功,召唤了大风,由于是海上,风变得十分大,经过每一座桥都有不可避免的风阻碍YYD,YYD十分ddt,于是用泡芙贿赂了你,希望你能帮他找出一条承受的最大风力最小的路线。

    Input

    输入:第一行为两个用空格隔开的整数n(2<=n<=1000),m(1<=m<=2000),接下来读入m行由空格隔开的4个整数a,b(1<=a,b<=n,a<>b),c,d(1<=c,d<=1000),表示第i+1行第i座桥连接小岛a和b,从a到b承受的风力为c,从b到a承受的风力为d。

    Output

    输出:如果无法完成减肥计划,则输出NIE,否则第一行输出承受风力的最大值(要使它最小)

    Sample Input

    4 4
    1 2 2 4
    2 3 3 4
    3 4 4 4
    4 1 5 4

    Sample Output

    4

    HINT

    注意:通过桥为欧拉回路

    Source

    by poi

    Solution

    最大风力最小,典型的二分,那么二分风力,作为最大风力即可

    混合图欧拉回路,第一次见,大体上就是:

    欧拉回路是图G中的一个回路,经过每条边有且仅一次,称该回路为欧拉回路。具有欧拉回路的图称为欧拉图,简称E图。

    无向图中存在欧拉回路的条件:每个点的度数均为偶数。

    有向图中存在欧拉回路的条件:每个点的入度 = 出度。

    混合图就是一个含有有向边和无向边的图,混合图判欧拉回路时用的是最大流,原理及证明?我也不是很晓得...

    下面是大体的模型:

      把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。 
      好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入。如果每个点都是出 = 入,那么很明显,该图就存在欧拉回路。 
      现在的问题就变成了:我该改变哪些边,可以让每个点出 = 入?构造网络流模型。首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x,对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。之后,察看是否有满流的分配。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?察看流值分配,将所有流量非 0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。 
      由于是满流,所以每个入 > 出的点,都有x条边进来,将这些进来的边反向,OK,入 = 出了。对于出 > 入的点亦然。那么,没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。 
      所以,就这样,混合图欧拉回路问题,解了。 

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define maxn 2010
    #define maxm 1000100
    int n,m,minwind,maxwind,l,r,tot;
    struct Bridgenode{int a,b,c,d;}bridge[maxn];
    struct Edgenode{int to,next,cap;}edge[maxm];
    int head[maxn],cnt=1;
    void add(int u,int v,int w)
    {cnt++;edge[cnt].to=v;edge[cnt].cap=w;edge[cnt].next=head[u];head[u]=cnt;}
    void insert(int u,int v,int w)
    {add(u,v,w);add(v,u,0);}
    //
    #define inf 0x7fffffff
    int dis[maxn],cur[maxn],S,T,q[maxn<<1],du[maxn];
    bool bfs()
    {
        for (int i=S; i<=T; i++) dis[i]=-1;
        q[0]=S; dis[S]=0; int he=0,ta=1;
        while (he<ta)
            {
                int now=q[he++];
                for (int i=head[now]; i; i=edge[i].next)
                    if (edge[i].cap && dis[edge[i].to]==-1)
                        dis[edge[i].to]=dis[now]+1,q[ta++]=edge[i].to;
            }
        return dis[T]!=-1;
    }
    int dfs(int loc,int low)
    {
        if (loc==T) return low;
        int w,used=0;
        for (int i=cur[loc]; i; i=edge[i].next)
            if (edge[i].cap && dis[edge[i].to]==dis[loc]+1)
                {
                    w=dfs(edge[i].to,min(low-used,edge[i].cap));
                    edge[i].cap-=w; edge[i^1].cap+=w;
                    used+=w; if (edge[i].cap) cur[loc]=i;
                    if (used==low) return low;
                }
        if (!used) dis[loc]=-1;
        return used;
    }
    int dinic()
    {
        int tmp=0;
        for (int i=1; i<=n; i++) if (du[i]&1) return -1;
        while (bfs())
            {
                for (int i=S; i<=T; i++) cur[i]=head[i];
                tmp+=dfs(S,inf);
            }
        return tmp;
    }
    //
    inline void make(int x)
    {
        S=0,T=n+1;
        memset(head,0,sizeof(head)); cnt=1;
        memset(du,0,sizeof(du)); tot=0;
        for (int i=1; i<=m; i++)
        {
            if(bridge[i].c<=x) du[bridge[i].a]--,du[bridge[i].b]++;
            if(bridge[i].d<=x) insert(bridge[i].b,bridge[i].a,1);
        }
        for (int i=1; i<=n; i++)
            if (du[i]>0) tot+=du[i]/2,insert(S,i,du[i]/2);
                else insert(i,T,-du[i]/2);
    }
    int main()
    {
        n=read(),m=read(); minwind=inf; maxwind=-inf;
        for (int a,b,c,d,i=1; i<=m; i++)
            {
                a=read(),b=read(),c=read(),d=read();
                if (c>d) swap(a,b),swap(c,d);
                bridge[i].a=a,bridge[i].b=b,bridge[i].c=c,bridge[i].d=d;
                minwind=min(c,minwind); maxwind=max(d,maxwind);
            }
        l=minwind; r=maxwind;
        while (l<=r)
            {
                int mid=(l+r)>>1;
                make(mid);
                int maxflow=dinic();
                if (maxflow==tot) r=mid-1;
                    else l=mid+1;
            }
        if (l==maxwind+1) {puts("NIE");return 0;}
        printf("%d
    ",l);
        return 0;
    }

    好厉害的东西QAQ...以前只听说过,没见过QAQ...

  • 相关阅读:
    shell---telnet shell实现
    设计模式-建造者模式
    关于Http2
    转载Resharper使用
    设计模式-原型模式
    设计模式-代理模式
    设计模式-装饰器模式
    设计模式-简单工厂和策略模式
    C#直接发送打印机命令到打印机及ZPL常用打印命令
    C#打印机操作类
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5364494.html
Copyright © 2011-2022 走看看