zoukankan      html  css  js  c++  java
  • 算法复习——欧拉回路混合图(bzoj2095二分+网络流)

    题目:

    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

    注意:通过桥为欧拉回路

    题解:

      在二分答案后的图一定是个无向边+单向边的混合图,混合图的欧拉回路具体求法如下:

      把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。 因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。

      好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入。如果每个点都是出 = 入,那么很明显,该图就存在欧拉回路。

      现在的问题就变成了:我该改变哪些边,可以让每个点出 = 入?构造网络流模型。

      首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x,对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。
      之后,察看从S发出的所有边是否满流。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?察看流值分配,将所有流量非 0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。 
      由于是满流,所以每个入 > 出的点,都有x条边进来,将这些进来的边反向,OK,入 = 出了。对于出 > 入的点亦然。那么,没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。 
      所以,就这样,混合图欧拉回路问题,解了。

    代码:

      md因为边的数量初始化为0一直没检查出来错在哪·····下次要注意细节了····

      

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int N=1005;
    const int M=4005;
    struct node
    {
      int from,go;
      int val1,val2;
    }edge[M];
    int n,m,tot,father[N],size[N],chu[N],ru[N],src,des,maxx,temp;
    int first[N],go[M*2],next[M*2],rest[M*2],lev[N],cur[N],totl;
    inline int getfa(int a)
    {
      if(father[a]==a)  return a;
      father[a]=getfa(father[a]);
      return father[a];
    }
    inline void combfa(int a,int b)
    {
      int fa=getfa(a);
      int fb=getfa(b);
      if(fa!=fb)
        father[fa]=fb,size[fb]+=size[fa];
    }
    inline void comb(int a,int b,int c)
    {
      next[++totl]=first[a],first[a]=totl,go[totl]=b,rest[totl]=c;
      next[++totl]=first[b],first[b]=totl,go[totl]=a,rest[totl]=0;
    }
    inline bool bfs()
    {
      for(int i=src;i<=des;i++)  cur[i]=first[i],lev[i]=-1;
      static int que[N],tail,u,v;
      que[tail=1]=src;
      lev[src]=0;
      for(int head=1;head<=tail;head++)
      {
        u=que[head];
        for(int e=first[u];e;e=next[e])
        {
          if(lev[v=go[e]]==-1&&rest[e])
          {
            lev[v]=lev[u]+1;
            que[++tail]=v;
            if(v==des)  return true;
          }
        }
      }
      return false;
    }
    inline int dinic(int u,int flow)
    {
      if(u==des)
        return flow;
      int res=0,delta,v;
      for(int &e=cur[u];e;e=next[e])
      {
        if(lev[v=go[e]]>lev[u]&&rest[e])
        {
          delta=dinic(v,min(flow-res,rest[e]));
          if(delta)
          {
            rest[e]-=delta;
            rest[e^1]+=delta;
            res+=delta;
            if(res==flow)  break;
          }
        }
      }
      if(flow!=res)  lev[u]=-1;
      return res;
    }
    inline void maxflow()
    {
      while(bfs())
        temp+=dinic(src,100000000);
    }
    inline bool check(int limit)
    {
      memset(chu,0,sizeof(chu));
      memset(ru,0,sizeof(ru));
      memset(first,0,sizeof(first));
      src=0,des=n+1,maxx=0,temp=0,totl=1;
      for(int i=1;i<=n;i++)
        father[i]=i,size[i]=1;
      for(int i=1;i<=m;i++)
      {
        if(edge[i].val1<=limit&&edge[i].val2<=limit)//无向边定向 
        {  
          comb(edge[i].from,edge[i].go,1); 
          chu[edge[i].from]++;
          ru[edge[i].go]++;
          combfa(edge[i].go,edge[i].from);
         }
        else
          if(edge[i].val1<=limit)
          {
            chu[edge[i].from]++;
            ru[edge[i].go]++;
            combfa(edge[i].from,edge[i].go); 
           }
          else
            if(edge[i].val2<=limit)
            { 
              chu[edge[i].go]++;
              ru[edge[i].from]++;
              combfa(edge[i].from,edge[i].go);
            }
            else return false;
      }
      if(size[getfa(1)]!=n)  return false;
      for(int i=1;i<=n;i++)
      { 
        if(chu[i]==ru[i])  continue;
        if(ru[i]<chu[i])
        {
          if((chu[i]-ru[i])%2==1)  return false;
          else  comb(src,i,(chu[i]-ru[i])/2),maxx+=((chu[i]-ru[i])/2);
        }
        else
        {
          if((ru[i]-chu[i])%2==1)  return false;
          else comb(i,des,(ru[i]-chu[i])/2);
        }
      }
      maxflow();
      if(temp!=maxx)  return false;
      else return true;
    }
    inline bool cmp(node a,node b)
    {
      return a.val1<b.val1;
    }
    int main()
    {
      //freopen("a.in","r",stdin);
      scanf("%d%d",&n,&m);
      int a,b,c,d,ans=0;
      for(int i=1;i<=m;i++)
      {
        scanf("%d%d%d%d",&a,&b,&c,&d);
        edge[i].from=a;
        edge[i].go=b;
        edge[i].val1=c;
        edge[i].val2=d;
      }
      int left=1,right=1000;
      while(left<=right) 
      {
        int mid=(left+right)/2;
        if(check(mid))  right=mid-1,ans=mid;
        else left=mid+1;
      }
      if(!ans)  cout<<"NIE"<<endl;
      else cout<<ans<<endl;
      return 0;
    }
  • 相关阅读:
    Apache 虚拟主机 VirtualHost 配置
    EAX、ECX、EDX、EBX寄存器的作用
    Python中文文档 目录(转载)
    八度
    POJ 3268 Silver Cow Party (最短路)
    POJ 2253 Frogger (求每条路径中最大值的最小值,Dijkstra变形)
    2013金山西山居创意游戏程序挑战赛——复赛(1) HDU 4557 非诚勿扰 HDU 4558 剑侠情缘 HDU 4559 涂色游戏 HDU 4560 我是歌手
    HDU 4549 M斐波那契数列(矩阵快速幂+欧拉定理)
    UVA 11624 Fire! (简单图论基础)
    HDU 3534 Tree (树形DP)
  • 原文地址:https://www.cnblogs.com/AseanA/p/7472389.html
Copyright © 2011-2022 走看看