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

4 4
1 2 2 4
2 3 3 4
3 4 4 4
4 1 5 4
技术分享

Sample Output

4

题解:混合图欧拉回路做法:先将所有边随意定向,然后从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 动态加边网络流的主要内容,如果未能解决你的问题,请参考以下文章

Bzoj2095 [Poi2010]Bridges

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

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

*BZOJ2095: [Poi2010]Bridges

bzoj 2095 Poi2010 Bridges 混合图欧拉回路

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