【BZOJ2095】 Bridge

 

Time Limit: 1000 ms   Memory Limit: 128 MB

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

  题目要求的,是对于每一座桥定向后来的欧拉回路。(这个理解错了我就彻底懵逼了)

  可以考虑二分答案$ans$:对于每一座桥,只将边权小于等于$ans$的边加入图中。这是一个混合图,用网络流求解是否为欧拉回路即可。若是则$r=mid-1$,否则$l=mid+1$。

  最后的答案落在$l$。

  如果$l$大过所有边权的最大值,那么就是NIE。


#include <cstdio>
#include <queue>
using namespace std;
const int N=1010,M=2010,INF=2147000000;
int n,m,maxw,e[M][4];
int h[N],tot,in[N],out[N];
int S,T,dis[N],cur[N];
queue<int> q;
struct Edge{int v,f,next;}g[M*8];
inline int max(int x,int y){return x>y?x:y;}
inline void addEdge(int u,int v,int f){
    g[++tot].v=v; g[tot].f=f; g[tot].next=h[u]; h[u]=tot;
    g[++tot].v=u; g[tot].f=0; g[tot].next=h[v]; h[v]=tot;
}
bool bfs(){
    while(!q.empty()) q.pop();
    q.push(S);
    for(int i=1;i<=T;i++) dis[i]=-1;
    dis[S]=0;
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=h[u],v;i;i=g[i].next)
            if(g[i].f&&dis[v=g[i].v]==-1){
                dis[v]=dis[u]+1;
                if(v==T) return true;
                q.push(v);
            }
    }
    return dis[T]!=-1;
}
int dfs(int u,int delta){
    if(u==T) return delta;
    int ret=0,get;
    for(int i=cur[u],v;i&&delta;i=g[i].next)
        if(g[i].f&&dis[v=g[i].v]==dis[u]+1){
            get=dfs(v,min(delta,g[i].f));
            g[i].f-=get;
            g[i^1].f+=get;
            if(g[i].f) cur[u]=i;
            delta-=get;
            ret+=get;
        }
    if(!ret) dis[u]=-1;
    return ret;
}
int dinic(){
    int ret=0;
    while(bfs()){
        for(int i=1;i<=T;i++) cur[i]=h[i];
        ret+=dfs(S,INF);
    }
    return ret;
}
bool check(int up){
    tot=1;
    for(int i=1;i<=T;i++) in[i]=out[i]=h[i]=0;
    for(int i=1;i<=m;i++){
        if(e[i][2]<=up)
            out[e[i][0]]++,in[e[i][1]]++;
        if(e[i][3]<=up)
            addEdge(e[i][0],e[i][1],1);
    }
    int sum=0;
    for(int i=1;i<=n;i++){
        if(!in[i]&&!out[i]) return false;
        if((in[i]-out[i])%2) return false;
        if(in[i]>out[i]) 
            addEdge(i,T,(in[i]-out[i])/2);
        else if(out[i]>in[i])
            addEdge(S,i,(out[i]-in[i])/2),sum+=(out[i]-in[i])/2;
    }
    int get=dinic();
    return get==sum;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&e[i][0],&e[i][1],&e[i][2],&e[i][3]);
        maxw=max(maxw,max(e[i][2],e[i][3]));
        if(e[i][2]>e[i][3])
            swap(e[i][0],e[i][1]),swap(e[i][2],e[i][3]);
    }
    S=n+1; T=n+2;
    int l=1,r=maxw,mid;
    while(l<=r){
        mid=(l+r)>>1;
        if(check(mid)) r=mid-1;
        else l=mid+1;
    }
    if(l>maxw) puts("NIE");
    else printf("%d
",l);
    return 0;
}
奇妙代码
原文地址:https://www.cnblogs.com/RogerDTZ/p/8024521.html