【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\n",l);
    return 0;
}

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

posted @ 2016-04-07 17:23  DaD3zZ  阅读(285)  评论(0编辑  收藏  举报