POI2010 Mos-Bridges(二分答案+欧拉回路+网络流)

【题目描述】

YYD 为了减肥,他来到了瘦海,这是一个巨大的海,海中有 n nn 个小岛,小岛之间有 m mm 座桥连接,两个小岛之间不会有两座桥,并且从一个小岛可以到另外任意一个小岛。现在 YYD 想骑单车从小岛 1 11 出发,骑过每一座桥,到达每一个小岛,然后回到小岛 1 11。霸中同学为了让 YYD 减肥成功,召唤了大风,由于是海上,风变得十分大,经过每一座桥都有不可避免的风阻碍 YYD,YYD 十分 ddt,于是用泡芙贿赂了你,希望你能帮他找出一条承受的最大风力最小的路线。

【输入格式】

第一行为两个用空格隔开的整数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。

【输出格式】

如果无法完成减肥计划,则输出 NIE,否则第一行输出承受风力的最大值(要使它最小)

【样例输入】

4 4

1 2 2 4

2 3 3 4

3 4 4 4

4 1 5 4

【样例输出】

4

【备注】

注意:通过桥为欧拉回路

【题目分析】

要让最大值最小,显然是二分答案的套路,所以我们就去二分这个最大值,将所有不大于这个值的边加入图中,然后检查是否构成欧拉回路。

然后问题也就来了,单纯的无向图和有向图的欧拉回路好判,但如何在混合图中去判欧拉回路?

VANVAN没想到就是网络流啊。。。。。。

首先我们将所有无向边任意定向,统计一下所有点出入度数,如果二者奇偶性不同,那么无解(将一条无向边反向后出入度变化2),所以每个点向源汇点连一条自身出入度差值的一半的边,表示需要转向这么多次。

那么问题就转化为匹配问题,如果最后最大流流满,那么就一定对应原图中存在欧拉回路。

【代码~】

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=1e3+10;
const int MAXM=4e3+10;
const int MAXP=1e6+10;
const int INF=0x3f3f3f3f;

int Read()
{
	int i=0,f=1;
	char c;
	for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
	if(c=='-')
	  f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())
	  i=(i<<3)+(i<<1)+c-'0';
	return i*f;
}

int n,m,cnt;
int s=0,t=1001;
int minn=INF,maxx=0;
int head[MAXN],depth[MAXN],cur[MAXN];
int nxt[MAXP],to[MAXP],w[MAXP];
int from[MAXM],too[MAXM],w1[MAXM],w2[MAXM];
int du[MAXN],tot;

void Add(int x,int y,int z)
{
	nxt[cnt]=head[x];
	head[x]=cnt;
	to[cnt]=y;
	w[cnt]=z;
	cnt++;
}

void add(int x,int y,int z)
{
	Add(x,y,z);
	Add(y,x,0);
}

bool bfs(){
	memset(depth,0,sizeof(depth));
	queue<int> q;
	q.push(s);
	depth[s]=1;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=head[u];i!=-1;i=nxt[i])
		{
			int v=to[i];
			if(w[i]&&depth[v]==0)
			{
				depth[v]=depth[u]+1;
				q.push(v);
			}
		}
	}
	if(depth[t]==0)
	  return false;
	return true;
}

int dfs(int u,int dist)
{
	if(u==t)
	  return dist;
	for(int &i=cur[u];i!=-1;i=nxt[i])
	{
		int v=to[i];
		if(w[i]&&depth[v]==depth[u]+1)
		{
			int di=dfs(v,min(dist,w[i]));
			if(di>0)
			{
				w[i]-=di;
				w[i^1]+=di;
				return di;
			}
		}
	}
	return 0;
}

int dinic()
{
	int ans=0;
	while(bfs())
	{
		for(int i=s;i<=t;++i)
		  cur[i]=head[i];
		while(int d=dfs(s,INF))
		  ans+=d;
	}
	return ans;
}

void build(int mid)
{
	memset(head,-1,sizeof(head));
	memset(du,0,sizeof(du));
	cnt=0;
	tot=0;
	for(int i=1;i<=m;++i)
	{
		if(w1[i]<=mid)
		  --du[from[i]],++du[too[i]];
		if(w2[i]<=mid)
		  add(too[i],from[i],1);
	}
	for(int i=1;i<=n;++i)
	  if(du[i]>0)
	    tot+=du[i]>>1,add(s,i,du[i]>>1);
	  else 
	    if(du[i]<0)
		  add(i,t,(-du[i])>>1);
}

bool check(int mid)
{
	build(mid);
	for(int i=1;i<=n;++i)
	  if(du[i]&1)
	    return false;
	if(dinic()==tot)
	  return true;
	return false;
}

int main()
{
	n=Read(),m=Read();
	for(int i=1;i<=m;++i)
	{
		from[i]=Read(),too[i]=Read(),w1[i]=Read(),w2[i]=Read();
		if(w1[i]>w2[i])
		  swap(w1[i],w2[i]),swap(from[i],too[i]);
		minn=min(minn,w1[i]);
		maxx=max(maxx,w2[i]);
	}
	int l=minn,r=maxx;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid))
		  r=mid-1;
		else 
		  l=mid+1;
	}
	if(l==maxx+1)
	  puts("NIE");
	else 
	  cout<<l;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/g21glf/article/details/83815713