BZOJ2095:[POI2010]Bridges(最大流,欧拉图)

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

注意:通过桥为欧拉回路

Solution

首先二分一下答案,然后问题就变成了求混合图的欧拉回路。

这是网络流比较经典的一个问题,详细做法可以看这篇博客

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cstdio>
  5 #include<queue>
  6 #define N (5009)
  7 using namespace std;
  8 
  9 struct Edge{int to,next,flow;}edge[N<<1];
 10 int n,m,a[N],b[N],c[N],d[N];
 11 int s,e=5000,tot,Depth[N],Deg[N];
 12 int head[N],num_edge;
 13 queue<int>q;
 14 
 15 void add(int u,int v,int l)
 16 {
 17     edge[++num_edge].to=v;
 18     edge[num_edge].next=head[u];
 19     edge[num_edge].flow=l;
 20     head[u]=num_edge;
 21 }
 22 
 23 int DFS(int x,int low)
 24 {
 25     if (x==e || !low) return low;
 26     int f=0;
 27     for (int i=head[x]; i; i=edge[i].next)
 28         if (Depth[edge[i].to]==Depth[x]+1)
 29         {
 30             int Min=DFS(edge[i].to,min(low,edge[i].flow));
 31             edge[i].flow-=Min;
 32             edge[((i-1)^1)+1].flow+=Min;
 33             f+=Min; low-=Min;
 34             if (!low) break;
 35         }
 36     if (!f) Depth[x]=-1;
 37     return f;
 38 }
 39 
 40 bool BFS(int s,int e)
 41 {
 42     memset(Depth,0,sizeof(Depth));
 43     Depth[s]=1; q.push(s);
 44     while (!q.empty())
 45     {
 46         int x=q.front(); q.pop();
 47         for (int i=head[x]; i; i=edge[i].next)
 48             if (!Depth[edge[i].to] && edge[i].flow)
 49             {
 50                 Depth[edge[i].to]=Depth[x]+1;
 51                 q.push(edge[i].to);
 52             }
 53     }
 54     return Depth[e];
 55 }
 56 
 57 int Dinic(int s,int e)
 58 {
 59     int ans=0;
 60     while (BFS(s,e)) ans+=DFS(s,0x7fffffff);
 61     return ans;
 62 }
 63 
 64 bool check(int lim)
 65 {
 66     memset(head,0,sizeof(head));
 67     num_edge=0;
 68     
 69     for (int i=1; i<=m; ++i)
 70     {
 71         if (c[i]>lim) return 0;
 72         if (d[i]<=lim) add(a[i],b[i],1), add(b[i],a[i],0);
 73     }
 74     for (int i=1; i<=n; ++i)
 75     {
 76         if (Deg[i]<0) add(s,i,-Deg[i]/2), add(i,s,0);
 77         if (Deg[i]>0) add(i,e,Deg[i]/2), add(e,i,0);
 78     }
 79     return Dinic(s,e)==tot/2;
 80 }
 81 
 82 int main()
 83 {
 84     scanf("%d%d",&n,&m);
 85     for (int i=1; i<=m; ++i)
 86     {
 87         scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
 88         if (c[i]>d[i]) swap(a[i],b[i]), swap(c[i],d[i]);
 89         Deg[a[i]]--, Deg[b[i]]++;
 90     }
 91     for (int i=1; i<=n; ++i)
 92         if (Deg[i]%2) {puts("NIE"); return 0;}
 93         else tot+=abs(Deg[i]/2);
 94     int l=1,r=1000,ans=-1;
 95     while (l<=r)
 96     {
 97         int mid=(l+r)>>1;
 98         if (check(mid)) ans=mid, r=mid-1;
 99         else l=mid+1;
100     }
101     printf("%d\n",ans);
102 }
posted @ 2019-02-27 14:03  Refun  阅读(156)  评论(0编辑  收藏  举报