BZOJ2095[Poi2010]Bridges 动态加边网络流
Posted CQzhangyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2095[Poi2010]Bridges 动态加边网络流相关的知识,希望对你有一定的参考价值。
【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
1 2 2 4
2 3 3 4
3 4 4 4
4 1 5 4
Sample Output
题解:混合图欧拉回路做法:先将所有边随意定向,然后从S向所有度数为正的点连边,度数为负的点向T连边,再连上原图的反向边,跑最大流看是否有解即可。
对于本题,我们可以先对于每条边选取阻力较小的那个方向,然后将按另一个方向的阻力排序,从小到大扔到图中,如果扔进去之后满流了,则输出答案即可。
网上部分用二分做的代码有问题,可以被hack。
#include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <algorithm> using namespace std; int n,m,ans,sum,cnt,S,T; struct node { int a,b,c,d; }p[2010]; int to[10010],next[10010],val[10010],head[1010],d[1010]; queue<int> q; bool cmp(const node &a,const node &b) { return a.d<b.d; } inline void add(int a,int b,int c) { to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++; to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++; } int dfs(int x,int mf) { if(x==T) return mf; int i,k,temp=mf; for(i=head[x];i!=-1;i=next[i]) if(d[to[i]]==d[x]+1&&val[i]) { k=dfs(to[i],min(temp,val[i])); if(!k) d[to[i]]=0; val[i]-=k,val[i^1]+=k,temp-=k; if(!temp) break; } return mf-temp; } int bfs() { memset(d,0,sizeof(d)); while(!q.empty()) q.pop(); int i,u; q.push(S),d[S]=1; while(!q.empty()) { u=q.front(),q.pop(); for(i=head[u];i!=-1;i=next[i]) if(!d[to[i]]&&val[i]) { d[to[i]]=d[u]+1; if(to[i]==T) return 1; q.push(to[i]); } } return 0; } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘) f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+(gc^‘0‘),gc=getchar(); return ret*f; } int main() { n=rd(),m=rd(); int i; for(i=1;i<=m;i++) { p[i].a=rd(),p[i].b=rd(),p[i].c=rd(),p[i].d=rd(); if(p[i].c>p[i].d) swap(p[i].a,p[i].b),swap(p[i].c,p[i].d); d[p[i].a]++,d[p[i].b]--; ans=max(ans,p[i].c); } sort(p+1,p+m+1,cmp); memset(head,-1,sizeof(head)); S=0,T=n+1; for(i=1;i<=n;i++) { if(d[i]&1) { printf("NIE"); return 0; } d[i]>>=1; if(d[i]>0) add(S,i,d[i]),sum+=d[i]; if(d[i]<0) add(i,T,-d[i]); } if(sum) for(i=1;i<=m;i++) { add(p[i].a,p[i].b,1); ans=max(ans,p[i].d); while(bfs()) sum-=dfs(S,1<<30); if(!sum) break; } if(sum) printf("NIE"); else printf("%d",ans); return 0; }
以上是关于BZOJ2095[Poi2010]Bridges 动态加边网络流的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 2095 [Poi2010]Bridges 判断欧拉维护,最大流+二分
BZOJ2095[Poi2010]Bridges 动态加边网络流