Bzoj2095 [Poi2010]Bridges

 

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 983  Solved: 330

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

 

希望每一个点进这篇题解的人都能看到上面的HINT

题目翻译真是恶意满满,我还以为这是道二分+MST的水题呢(谁叫你自己不看完题面)

注意到欧拉回路的条件以后,这变成了一道二分+网络流的水题

 

网络流 二分答案 混合图欧拉回路

二分答案很显然。

设当前check的答案是lim,那么c小于lim而d大于lim的边相当于有向边,c,d均小于lim的边相当于无向边。

我们将无向边定向为c,d,和有向边一起统计度数。若一条边是无向边,则从它的b向a连边,容量为1,表示可以改变这条边的方向以改变两端点的1点度数

设deg表示入度减出度的值

从源点S向deg大于0的点连边,容量为deg/2,从deg小于0的点向T连边,容量为-deg/2

跑网络流,如果S的出弧满流,那么方案可行。←满流说明如果那些容量为1的弧可以调节每个点的出入度至平衡。

 

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<vector>
  7 #include<queue>
  8 using namespace std;
  9 const int INF=0x3f3f3f3f;
 10 const int mxn=2010;
 11 int read(){
 12     int x=0,f=1;char ch=getchar();
 13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 15     return x*f;
 16 }
 17 struct edge{
 18     int v,nxt,f;
 19 }e[mxn<<2];
 20 int hd[mxn],mct=0;
 21 void add_edge(int u,int v,int w){
 22     e[++mct].nxt=hd[u];e[mct].v=v;e[mct].f=w;hd[u]=mct;return;
 23 }
 24 void insert(int u,int v,int w){
 25     add_edge(u,v,w);
 26     add_edge(v,u,0);
 27 }
 28 int n,m,S,T;
 29 int d[mxn];
 30 bool BFS(){
 31     memset(d,0,sizeof d);
 32     queue<int>q;
 33     q.push(S);d[S]=1;
 34     while(!q.empty()){
 35         int u=q.front();q.pop();
 36         for(int i=hd[u];i;i=e[i].nxt){
 37             int v=e[i].v;
 38             if(!e[i].f || d[v])continue;
 39             d[v]=d[u]+1;
 40             q.push(v);
 41         }
 42     }
 43     return d[T];
 44 }
 45 int DFS(int u,int lim){
 46     if(u==T)return lim;
 47     int f=0,tmp;
 48     for(int i=hd[u];i;i=e[i].nxt){
 49         int v=e[i].v;
 50         if(d[v]==d[u]+1 && e[i].f && (tmp=DFS(e[i].v,min(lim,e[i].f)))){
 51             e[i].f-=tmp;
 52             e[i^1].f+=tmp;
 53             f+=tmp;
 54             lim-=tmp;
 55             if(!lim)return f;
 56         }
 57     }
 58     d[u]=0;
 59     return f;
 60 }
 61 int Dinic(){
 62     int res=0;
 63     while(BFS())res+=DFS(S,INF);
 64     return res;
 65 }
 66 struct bridge{
 67     int a,b,c,d;
 68 }br[mxn];
 69 int deg[mxn],cnt=0;
 70 bool Build(int lim){
 71     memset(hd,0,sizeof hd);mct=1;
 72     memset(deg,0,sizeof deg);cnt=0;
 73     S=0;T=n+1;
 74     for(int i=1;i<=m;i++){
 75         if(br[i].c<=lim)deg[br[i].a]--,deg[br[i].b]++;
 76         if(br[i].d<=lim)insert(br[i].b,br[i].a,1);
 77     }
 78     for(int i=1;i<=n;i++){
 79         if(deg[i]&1)return 0;
 80         if(deg[i]>0)insert(S,i,deg[i]/2),cnt+=deg[i]/2;
 81         else insert(i,T,-deg[i]/2);
 82     }
 83     return 1;
 84 }
 85 int mn,mx;
 86 void solve(){
 87     int ans=-1;
 88     while(mn<=mx){
 89         int mid=(mn+mx)>>1;
 90         if(Build(mid) && (cnt==Dinic())){
 91             ans=mid;
 92             mx=mid-1;
 93         }
 94         else mn=mid+1;
 95     }
 96     if(ans==-1)puts("NIE");
 97     else printf("%d\n",ans);
 98     return;
 99 }
100 int main(){
101     int i,j;
102     n=read();m=read();
103     mn=INF;mx=0;
104     for(i=1;i<=m;i++){
105         br[i].a=read();br[i].b=read();br[i].c=read();br[i].d=read();
106         if(br[i].c>br[i].d){
107             swap(br[i].c,br[i].d);
108             swap(br[i].a,br[i].b);
109         }
110         mn=min(mn,br[i].c);
111         mx=max(mx,br[i].d);
112     }
113     solve();
114     return 0;
115 }

 

posted @ 2017-07-09 11:00 SilverNebula 阅读(...) 评论(...) 编辑 收藏
AmazingCounters.com