[BZOJ2095][Poi2010]Bridges 二分+网络流

2095: [Poi2010]Bridges

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 1187  Solved: 408
[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

 

注意:通过桥为欧拉回路

 

首先我们二分答案,之后我们用可行边建图,发现是混合图的欧拉回路问题,用网络流解决。

对于无向边,我们给它随意定向,之后看每个点的入度出度之差的绝对值tmp是否为2的倍数。

对于入度大于出度的点,我们从这个点向汇点连一条容量为tmp/2的边。

对于入度小于出度的点,我们从源点向这个点连一条容量为tmp/2的边。

对于每一条无向边,我们沿定的向连一条容量为1的边。

查询是否满流。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<algorithm>
  7 using namespace std;
  8 int n,m;
  9 int head[2002],cnt;
 10 struct data {
 11     int to,next,w;
 12 }e[80008];
 13 void add(int u,int v,int c){e[cnt].to=v;e[cnt].next=head[u];e[cnt].w=c;head[u]=cnt++;}
 14 struct data1 {
 15     int a,b,c,d;
 16 }t[2002];
 17 int ru[2002],cu[2002];
 18 int q[2002];
 19 bool vis[2002];
 20 int dis[2002];
 21 bool bfs() {
 22     memset(dis,-1,sizeof(dis));
 23     int h=0,t=1;
 24     q[h]=0;
 25     vis[0]=1;
 26     dis[0]=0;
 27     while(h!=t) {
 28         int now=q[h];h++;vis[now]=0;if(h==2000) h=0;
 29         for(int i=head[now];i>=0;i=e[i].next) {
 30             int to=e[i].to;
 31             if(e[i].w>0&&dis[to]<0) {
 32                 dis[to]=dis[now]+1;
 33                 if(!vis[to]){
 34                     vis[to]=1;
 35                     q[t++]=to;if(t==2000)t=0;
 36                 }
 37             }
 38         }
 39     }
 40     return dis[n+1]!=-1;
 41 }
 42 int dfs(int now,int a) {
 43     if(now==n+1||a==0) return a;
 44     int flow=0,f;
 45     for(int i=head[now];i>=0;i=e[i].next) {
 46         int to=e[i].to;
 47         if(dis[to]==dis[now]+1&&e[i].w>0) {
 48             f=dfs(to,min(a,e[i].w));
 49             e[i].w-=f;
 50             e[i^1].w+=f;
 51             flow+=f;
 52             a-=f;
 53             if(a==0) break;
 54         }
 55     }
 56     if(!flow) dis[now]=-1;
 57     return flow;
 58 }
 59 bool check(int mid) {
 60     cnt=0;
 61     memset(head,-1,sizeof(head));
 62     memset(ru,0,sizeof(ru));
 63     memset(cu,0,sizeof(cu));
 64     for(int i=1;i<=m;i++) {
 65         if(t[i].c<=mid) {
 66             if(t[i].d<=mid) {
 67                 add(t[i].a,t[i].b,1);
 68                 add(t[i].b,t[i].a,0);
 69                 cu[t[i].a]++;ru[t[i].b]++;
 70             }
 71             else {cu[t[i].a]++;ru[t[i].b]++;}
 72         }
 73         else if(t[i].d<=mid) {ru[t[i].a]++;cu[t[i].b]++;}
 74         else return 0;
 75     }
 76     int sum=0;
 77     for(int i=1;i<=n;i++) {
 78         if(abs(ru[i]-cu[i])&1) return 0;
 79         int tmp=abs(ru[i]-cu[i]);
 80         if(ru[i]<cu[i]) {add(0,i,tmp/2);add(i,0,0);}
 81         else if(ru[i]>cu[i]) {sum+=tmp/2;add(i,n+1,tmp/2);add(n+1,i,0);}
 82     }
 83     int ans=0;
 84     while(bfs()){ans+=dfs(0,2147483647);}
 85     return ans==sum;
 86 }
 87 int main() {
 88     scanf("%d%d",&n,&m);
 89     for(int i=1;i<=m;i++) {
 90         scanf("%d%d%d%d",&t[i].a,&t[i].b,&t[i].c,&t[i].d);
 91     }
 92     int l=0,r=1000;
 93     while(l<=r) {
 94         int mid=(l+r)>>1;
 95         if(check(mid)) r=mid-1;
 96         else l=mid+1;
 97     }
 98     if(r==1000) printf("NIE");
 99     else printf("%d",r+1);
100 }
View Code

 

posted @ 2017-10-25 12:58  wls001  阅读(163)  评论(0编辑  收藏  举报