BZOJ 2095: [Poi2010]Bridges

2095: [Poi2010]Bridges

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

by poi

分析:

最大值最小的问题...

二分答案,然后就转化成了混合图欧拉回路的存在性问题...可以参考POJ 1637

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
#define inf 0x3f3f3f3f
using namespace std;

const int maxn=1000+5,maxm=10000+5;

int n,m,S,T,tot,Min,Max,in[maxn],out[maxn],vis[maxm];
int cnt,hd[maxn],fl[maxm],to[maxm],pos[maxn],nxt[maxm];

struct M{
	int x,y,c,d;
}e[maxm];

inline void add(int x,int y,int s){
	fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
	fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++;
}

inline bool bfs(void){
	memset(pos,-1,sizeof(pos));
	int head=0,tail=0,q[maxn];
	pos[S]=0;q[0]=S;
	while(head<=tail){
		int top=q[head++];
		for(int i=hd[top];i!=-1;i=nxt[i])
			if(pos[to[i]]==-1&&fl[i])
				pos[to[i]]=pos[top]+1,q[++tail]=to[i];
	}
	return pos[T]!=-1;
}

inline int find(int v,int f){
	if(v==T) return f;
	int res=0,t;
	for(int i=hd[v];i!=-1&&f>res;i=nxt[i])
		if(pos[to[i]]==pos[v]+1&&fl[i])
			t=find(to[i],min(fl[i],f-res)),res+=t,fl[i]-=t,fl[i^1]+=t;
	if(!res) pos[v]=-1;
	return res;
}

inline int dinic(void){
	int res=0,t;
	while(bfs())
		while(t=find(S,inf))
			res+=t;
	return res;
}

inline bool check(int val){
	cnt=0;tot=0;
	memset(in,0,sizeof(in));
	memset(hd,-1,sizeof(hd));
	memset(out,0,sizeof(out));
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=m;i++){
		if(e[i].c<=val) vis[i]+=1;
		if(e[i].d<=val) vis[i]+=2;
	}
	for(int i=1;i<=m;i++){
		if(vis[i]==3)
			in[e[i].y]++,out[e[i].x]++,add(e[i].x,e[i].y,1);
		else if(vis[i]==1)
			in[e[i].y]++,out[e[i].x]++;
		else if(vis[i]==2)
			in[e[i].x]++,out[e[i].y]++;
	}
	for(int i=1;i<=n;i++)
		if(abs(in[i]-out[i])&1)
			return false;
	for(int i=1;i<=n;i++)
		if(in[i]<out[i])
			add(S,i,(out[i]-in[i])/2),tot+=(out[i]-in[i])/2;
		else if(in[i]>out[i])
			add(i,T,(in[i]-out[i])/2);
	if(dinic()==tot)
		return true;
	return false;
}

signed main(void){
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
#endif
	scanf("%d%d",&n,&m);Min=2333;Max=0;S=0,T=n+1;
	for(int i=1;i<=m;i++)
		scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].c,&e[i].d),
		Min=min(Min,min(e[i].c,e[i].d)),
		Max=max(Max,max(e[i].c,e[i].d));
	int l=Min,r=Max,ans=-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(check(mid))
			ans=mid,r=mid-1;
		else
			l=mid+1;
	}
	if(ans==-1) puts("NIE");
	else printf("%d\n",ans);	
	return 0;
}

  


By NeighThorn

posted @ 2017-04-10 17:50  NeighThorn  阅读(295)  评论(1编辑  收藏  举报