1. 程式人生 > >算法復習——歐拉回路混合圖(bzoj2095二分+網絡流)

算法復習——歐拉回路混合圖(bzoj2095二分+網絡流)

n) truct lin 歐拉圖 所有 mage borde algo stream

題目:

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;
}

算法復習——歐拉回路混合圖(bzoj2095二分+網絡流)