BZOJ2095: [Poi2010]Bridges

題解:php

二分答案以後就是混合圖(有向邊+無向邊)的歐拉回路問題。ios

如何判斷歐拉回路是否存在?網絡

把該圖的無向邊隨便定向,計算每一個點的入度和出度。若是有某個點出入度
之差爲奇數,那麼確定不存在歐拉回路。由於歐拉回路要求每點入度 = 出度,
也就是總度數爲偶數,存在奇數度點必不能有歐拉回路。
好了,如今每一個點入度和出度之差均爲偶數。那麼將這個偶數除以 2,得 x。
也就是說,對於每個點,只要將 x 條邊改變方向(入>出就是變入,出>入就是9
變出),就能保證出=入。若是每一個點都是出=入,那麼很明顯,該圖就存在歐拉
迴路。
如今的問題就變成了:我該改變哪些邊,可讓每一個點出=入?構造網絡流
模型。首先,有向邊是不能改變方向的,要之無用,刪。一開始不是把無向邊定
向了嗎?定的是什麼向,就把網絡構建成什麼樣,邊長容量上限 1。另新建 s 和
t。對於入>出的點 u,鏈接邊(u, t)、容量爲 x,對於出>入的點 v,鏈接邊(s, v),
容量爲 x(注意對不一樣的點 x 不一樣)。以後,察看是否有滿流的分配。有就是能
有歐拉回路,沒有就是沒有。歐拉回路是哪一個?察看流值分配,將全部流量非 0
(上限是 1,流值不是 0 就是 1)的邊反向,就能獲得每點入度=出度的歐拉圖。
因爲是滿流,因此每一個入>出的點,都有 x 條邊進來,將這些進來的邊反向,
OK,入=出了。對於出>入的點亦然。那麼,沒和 s、t 鏈接的點怎麼辦?和 s 連
接的條件是出>入,和 t 鏈接的條件是入>出,那麼這個既沒和 s 也沒和 t 鏈接的
點,天然早在開始就已經知足入=出了。那麼在網絡流過程當中,這些點屬於「中
間點」。咱們知道中間點流量不容許有累積的,這樣,進去多少就出來多少,反
向以後,天然仍保持平衡。
因此,就這樣,混合圖歐拉回路問題,解了。ide

代碼:spa

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<iostream>
  7 #include<vector>
  8 #include<map>
  9 #include<set>
 10 #include<queue>
 11 #include<string>
 12 #define inf 1000000000
 13 #define maxn 100000+5
 14 #define maxm 100000+5
 15 #define eps 1e-10
 16 #define ll long long
 17 #define pa pair<int,int>
 18 #define for0(i,n) for(int i=0;i<=(n);i++)
 19 #define for1(i,n) for(int i=1;i<=(n);i++)
 20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 22 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
 23 #define mod 1000000007
 24 using namespace std;
 25 inline int read()
 26 {
 27     int x=0,f=1;char ch=getchar();
 28     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 29     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
 30     return x*f;
 31 }
 32 int  n,m,s,t,maxflow,tot=1,head[maxn],cur[maxn],h[maxn];
 33 queue<int>q;
 34 bool can[maxn];
 35 int u[maxn],v[maxn],w1[maxn],w2[maxn],in[maxn],out[maxn],sum;
 36 struct edge{int go,next,v;}e[maxm];
 37 void add(int x,int y,int v)
 38 {
 39     e[++tot]=(edge){y,head[x],v};head[x]=tot;
 40     e[++tot]=(edge){x,head[y],0};head[y]=tot;
 41 }
 42 bool bfs()
 43 {
 44     for(int i=s;i<=t;i++)h[i]=-1;
 45     q.push(s);h[s]=0;
 46     while(!q.empty())
 47     {
 48         int x=q.front();q.pop();
 49         for(int i=head[x];i;i=e[i].next)
 50          if(e[i].v&&h[e[i].go]==-1)
 51          {
 52             h[e[i].go]=h[x]+1;q.push(e[i].go);
 53          }
 54     }
 55     return h[t]!=-1;
 56 }
 57 int dfs(int x,int f)
 58 {
 59     if(x==t) return f;
 60     int tmp,used=0;
 61     for(int i=cur[x];i;i=e[i].next)
 62      if(e[i].v&&h[e[i].go]==h[x]+1)
 63     {
 64         tmp=dfs(e[i].go,min(e[i].v,f-used));
 65         e[i].v-=tmp;if(e[i].v)cur[x]=i;
 66         e[i^1].v+=tmp;used+=tmp;
 67         if(used==f)return f;       
 68     }
 69     if(!used) h[x]=-1;
 70     return used;
 71 }
 72 void dinic()
 73 {
 74     maxflow=0;
 75     while(bfs())
 76     {
 77         for (int i=s;i<=t;i++)cur[i]=head[i];maxflow+=dfs(s,inf);
 78     }
 79 }
 80 bool check(int mid)
 81 {
 82     memset(head,0,sizeof(head));tot=1;
 83     memset(out,0,sizeof(out));
 84     memset(in,0,sizeof(in));
 85     sum=0;s=0;t=n+1;
 86     for1(i,m)
 87     {
 88         if(w1[i]<=mid)out[u[i]]++,in[v[i]]++;//有向邊計算入度和出度 
 89         if(w2[i]<=mid)add(v[i],u[i],1);//無向邊把剛纔假設的邊的反向邊加入表明咱們反悔的資本 
 90     }
 91     for1(i,n)if(abs(in[i]-out[i])&1)return 0;
 92     for1(i,n)
 93     {
 94         int x=in[i]-out[i];
 95         sum+=x>0?x>>1:0;
 96         if(x>0)add(s,i,x>>1);//入度太大了!派i去走x>>1條反悔邊!!! 
 97         if(x<0)add(i,t,(-x)>>1);//同理 
 98     }
 99     dinic();
100     return maxflow==sum;
101 }
102 int main()
103 {
104     freopen("input.txt","r",stdin);
105     freopen("output.txt","w",stdout);
106     n=read();m=read();
107     int l=inf,r=-inf;
108     for1(i,m)
109     {
110         u[i]=read();v[i]=read();w1[i]=read();w2[i]=read();
111         if(w1[i]>w2[i])swap(w1[i],w2[i]),swap(u[i],v[i]);
112         l=min(l,w1[i]);r=max(r,w2[i]);
113     }
114     while(l<=r)
115     {
116         int mid=(l+r)>>1;
117         if(check(mid))r=mid-1;else l=mid+1;
118     }
119     if(!check(l))printf("NIE\n");else printf("%d\n",l);
120     return 0;
121 }
View Code

 

                                                               2095: [Poi2010]Bridges

 

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 243  Solved: 79
[Submit][Status]

Description

YYD爲了減肥,他來到了瘦海,這是一個巨大的海,海中有n個小島,小島之間有m座橋鏈接,兩個小島之間不會有兩座橋,而且從一個小島能夠到另外任意一個小島。如今YYD想騎單車從小島1出發,騎過每一座橋,到達每個小島,而後回到小島1。霸中同窗爲了讓YYD減肥成功,召喚了大風,因爲是海上,風變得十分大,通過每一座橋都有不可避免的風阻礙YYD,YYD十分ddt,因而用泡芙賄賂了你,但願你能幫他找出一條承受的最大風力最小的路線。code

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。blog

Output

輸出:若是沒法完成減肥計劃,則輸出NIE,不然第一行輸出承受風力的最大值(要使它最小)ip

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 poiget

相關文章
相關標籤/搜索