BZOJ2095[Poi2010] Bridges

30 篇文章 0 订阅
23 篇文章 1 订阅

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:

人生第一道网络流,竟然交给了欧拉回路…

对于这道题,首先最大风力最小,显然是要先二分答案,然后这就转化成了一个经典的问题:混合图的欧拉回路判定问题。在本博客欧拉回路一文中另有阐述,此处不再赘述。(此处采用的POI的题目要求输出了方案)

#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<queue>
#define mp(a,b,c) (Edge){a,b,c}
#define M 2005
#define INF 1000000000
using namespace std;
struct Edge{int to,c,rev;};
int A[M],B[M],C[M],D[M],n,m,degreein[M],degreeout[M],S,T;
struct Dinic{
    int id[M],level[M];
    vector<Edge>G[M];
    void Init(){
        for(int i=S;i<=T;i++)G[i].clear();
    }
    void Addedge(int s,int t,int c){
        G[s].push_back(mp(t,c,G[t].size()));
        G[t].push_back(mp(s,0,G[s].size()-1));
    }
    void BFS(int s){
        queue<int>Q;
        level[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int top=Q.front();Q.pop();
            for(int i=0;i<G[top].size();i++){
                int to=G[top][i].to;
                if(G[top][i].c==0||level[to]!=-1)continue;
                level[to]=level[top]+1;
                Q.push(to);
            }
        }
    }
    int dfs(int s,int t,int f){
        if(s==t)return f;
        for(int &i=id[s];i<G[s].size();i++){
            int to=G[s][i].to;
            if(level[to]>level[s]&&G[s][i].c){
                int d=dfs(to,t,min(f,G[s][i].c));
                if(d){
                    G[s][i].c-=d;
                    G[to][G[s][i].rev].c+=d;
                    return d;
                }
            }
        }
        return 0;
    }
    int maxflow(int s,int t){
        int maxflow=0;
        while(1){
            memset(level,-1,sizeof(level));
            memset(id,0,sizeof(id));
            BFS(s);
            if(level[t]==-1)return maxflow;
            int f;
            while(f=dfs(s,t,INF))maxflow+=f;
        }
    }
}Dinic;
bool check(int x){
    int full=0;
    memset(degreein,0,sizeof(degreein));
    memset(degreeout,0,sizeof(degreeout));
    Dinic.Init();
    for(int i=1;i<=m;i++){
        if(C[i]>x&&D[i]>x)return false;
        if(C[i]>x&&D[i]<=x){
            degreein[A[i]]++;
            degreeout[B[i]]++;
        }else{
            degreein[B[i]]++;
            degreeout[A[i]]++;
            if(C[i]<=x&&D[i]<=x)Dinic.Addedge(A[i],B[i],1);
        }
    }
    for(int i=1;i<=n;i++){
        int x=abs(degreein[i]-degreeout[i]);
        if(x&1)return false;
        if(degreein[i]>degreeout[i])Dinic.Addedge(i,T,x/2);
        else {Dinic.Addedge(S,i,x/2);full+=x/2;}
    }
    return Dinic.maxflow(S,T)==full;
}
int ID[M][M];
int ans[M],sz=0;
void Pf(int x){
    for(int i=1;i<=n;i++){
        if(!ID[x][i])continue;
        int t=ID[x][i];
        ID[x][i]=0;
        Pf(i);
        ans[++sz]=t;
    }
}
int main(){
    int L,R,res=-1;
    scanf("%d %d",&n,&m);
    S=0;T=n+1;
    for(int i=1;i<=m;i++){
        scanf("%d %d %d %d",&A[i],&B[i],&C[i],&D[i]);
        if(i==1||C[i]<L)L=C[i];
        if(i==1||C[i]>R)R=C[i];
        if(D[i]<L)L=D[i];
        if(D[i]>R)R=D[i];
        ID[A[i]][B[i]]=ID[B[i]][A[i]]=i;
    }
    while(L<=R){
        int mid=(L+R)>>1;
        if(check(mid)){
            res=mid;
            R=mid-1;
        }else L=mid+1;
    }
    if(res==-1)puts("NIE");
    else{
        printf("%d\n",res);
        check(res);
        for(int i=1;i<=m;i++){
            if(C[i]>res)ID[A[i]][B[i]]=0;
            if(D[i]>res)ID[B[i]][A[i]]=0;
        }
        for(int i=1;i<=n;i++)
            for(int j=0;j<Dinic.G[i].size();j++){
                int to=Dinic.G[i][j].to;
                if(to==T||to==S||Dinic.G[i][j].c==1)continue;
                ID[i][to]=0;
            }
        Pf(1);
        for(int i=sz;i>=1;i--)
            printf("%d%c",ans[i],i==1?'\n':' ');
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值