BZOJ 2095 Poi2010 Bridges

Posted zhangenming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2095 Poi2010 Bridges相关的知识,希望对你有一定的参考价值。

2095: [Poi2010]Bridges

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

 

注意:通过桥为欧拉回路

 

Source

 

题目说最大值最小很明显的二分      二分一下最大值,然后有一些边就不能通过了

这时候我们只需要判断一下存在不存在欧拉回路即可

欧拉回路的判定条件为  对于图上所有的点入度等于出度

我们二分限制最大值后有一些边变成了单向变,还有一些边是双向边

我们先不管有向边,把无向边随意定向  统一定成从x到y

首先要满足条件就是当前图的点的度数都是偶数,因为把一条边反向端点的出度入度之差改变了2,奇偶性不变

我们只要判断是否把部分已经定向的无向边反向以后可以满足度都是偶数这个条件

用网络流来判断  对于每条边,如果定向为x到y,则y向x连边,流量为1

对于每个点x,如果出度 - 入度大于0,源点向x连边,否则x向汇点连边

流量为度数差除以2    如果满流则说明可以

  

#include <bits/stdc++.h>
#define ll long long
#define inf 1e9+10
using namespace std;
inline int read(){
	int x=0;int f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();}
	while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
const int MAXN=1e4+10;
struct node{
	int y,next,flow,back;
}e[MAXN];
struct edge{
	int x,y,a,b;
}k[MAXN];
int linkk[MAXN],level[2100],s,t,len,n,m,q[3000],head,tail,in[MAXN],out[MAXN];
inline void insert(int x,int y,int f){
	e[++len].y=y;e[len].next=linkk[x];linkk[x]=len;e[len].flow=f;e[len].back=len+1;
	e[++len].y=x;e[len].next=linkk[y];linkk[y]=len;e[len].flow=0;e[len].back=len-1;
}
inline bool getlevel(){
	head=tail=0;
	memset(level,-1,sizeof(level));
	q[++tail]=s;level[s]=0;
	while(head<tail){
		int tn=q[++head];
		for(int i=linkk[tn];i;i=e[i].next){
			if(level[e[i].y]==-1&&e[i].flow){
				level[e[i].y]=level[tn]+1;
				q[++tail]=e[i].y;
			}
		}
	}
	return level[t]>=0;
}
inline int getmaxflow(int x,int flow){
	if(x==t) return flow;
	int f=0,d;
	for(int i=linkk[x];i;i=e[i].next){
		if(e[i].flow&&level[e[i].y]==level[x]+1){
			if(d=getmaxflow(e[i].y,min(flow-f,e[i].flow))){
				f+=d;e[i].flow-=d;e[e[i].back].flow+=d;
				if(f==flow) return flow;
			}
		}
	}
	if(f==0) level[x]=-1;
	return  f;
}
inline int dinic(){
	int ans=0,d;
	while(getlevel()){
		while(d=getmaxflow(s,inf)) ans+=d;
	}
	return ans;
}
inline bool build(int mid){
	memset(linkk,0,sizeof(linkk));len=0;
	for(int i=1;i<=n;i++) in[i]=out[i]=0;
	for(int i=1;i<=m;i++){
		if(k[i].a<=mid&&k[i].b<=mid){
			out[k[i].x]++;in[k[i].y]++;
			insert(k[i].y,k[i].x,1);
		}
		else if(k[i].a<=mid) out[k[i].x]++,in[k[i].y]++;
		else if(k[i].b<=mid) out[k[i].y]++,in[k[i].x]++;
	}
	int sum=0;
	for(int i=1;i<=n;i++){
		int x=abs(in[i]-out[i]);
		if(x&1) return false;
		if(in[i]>out[i]) insert(s,i,x/2),sum+=x/2;
		else if(in[i]<out[i]) insert(i,t,x/2);
	}
	int ans=dinic();
	return ans==sum;
}
int main(){
	//freopen("All.in","r",stdin);
	//freopen("zh.out","w",stdout);
	n=read();m=read();int l=inf;int r=0;s=0;t=n+1;
	for(int i=1;i<=m;i++){
		k[i].x=read();k[i].y=read();k[i].a=read();k[i].b=read();
		l=min(l,min(k[i].a,k[i].b));
		r=max(r,max(k[i].a,k[i].b));
	}
	int mx=-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(build(mid)) r=mid-1,mx=mid;
		else l=mid+1;
	}
	if(mx==-1) cout<<"NIE"<<endl;
	else cout<<mx<<endl;
}

  









以上是关于BZOJ 2095 Poi2010 Bridges的主要内容,如果未能解决你的问题,请参考以下文章

Bzoj2095 [Poi2010]Bridges

BZOJ2095[Poi2010]Bridges 动态加边网络流

bzoj 2095 [Poi2010]Bridges 判断欧拉维护,最大流+二分

*BZOJ2095: [Poi2010]Bridges

bzoj 2095 Poi2010 Bridges 混合图欧拉回路

bzoj 2095: [Poi2010]Bridges(二分法+混合图的欧拉回路)