BZOJ 2095: [Poi2010]Bridges 混合图欧拉回路

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/88420639

YYD为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个小岛可以到另外任意一个小岛。现在YYD想骑单车从小岛1出发,骑过每一座桥,到达每一个小岛,然后回到小岛1。霸中同学为了让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。
注意:通过桥为欧拉回路

二分答案之后只有小于等于mid的桥可以保留,有的是单向,有的是无向。
验证需要求无向图欧拉回路:
1:先检验每个点入度是否为偶数,这是最先的。
2:将每条无向边定向(随便定)。
3:每个点需要入度等于出度,但是随机定向不能满足。
出度大于入度的点,需要 出边改向数 - 入边改向数 = (outdrg - indrg) / 2
出度小于入度的点,需要 入边改向数 - 出边改向数 = (-outdrg + indrg) / 2
如果我们认为:1流量从定了向的无向边(也就是有向边)流往点A表示这条A的入边改向为出边,1流量从定了向的无向边(也就是有向边)流出点A表示这条A的出边改向为入边,那么根据流量守恒,出度大于入度的点需要从源点流入 (outdrg - indrg) / 2,而出度小于入度的点需要流向汇点(-outdrg + indrg) / 2,满流即有方案。

AC Code:

#include<bits/stdc++.h>
#define maxn 1005
#define maxm 10005
#define inf 0x3f3f3f3f
using namespace std;

int n,m,x[maxm],y[maxm],c1[maxm],c2[maxm],in[maxn];
int info[maxn],Prev[maxm],to[maxm],cap[maxm],cnt_e=1;
void Node(int u,int v,int c){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cap[cnt_e]=c; }
void Line(int u,int v,int c,int d=0){ Node(u,v,c),Node(v,u,d); }
int S , T , dis[maxn];

int aug(int now,int Max)
{
	if(now == T) return Max;
	int inc , st = Max;
	for(int i=info[now];i;i=Prev[i])
		if(cap[i] && dis[to[i]] + 1 == dis[now])
		{
			inc = aug(to[i],min(cap[i],st));
			if(!inc) dis[to[i]] = -1;
			else st -= inc , cap[i] -= inc, cap[i^1] += inc;
			if(!st) break;
		}
	return Max - st;
}

bool BFS()
{
	static queue<int>q;
	memset(dis,-1,sizeof dis);
	q.push(T) , dis[T] = 0;
	for(int now;!q.empty();)
	{
		now = q.front() , q.pop();
		for(int i=info[now];i;i=Prev[i])
			if(cap[i^1] && dis[to[i]]==-1)
			{
				dis[to[i]] = dis[now] + 1;
				q.push(to[i]);
			}
	}
	return dis[S] != -1;
}

bool check(int mid)
{
	memset(info,0,sizeof info),cnt_e=1;
	for(int i=1;i<=n;i++)
	{
		if(in[i] & 1) return 0;
		if(in[i] < 0) Line(S,i,-in[i]/2);
		else if(in[i] > 0) Line(i,T,in[i]/2);
	}
	for(int i=1;i<=m;i++)
		if(c2[i]<=mid)
			Line(x[i],y[i],1);
	int stm = 0;
	for(;BFS();)
		stm+=aug(S,inf);
	for(int i=info[S];i;i=Prev[i])
		if(cap[i]) return 0;
	return 1;
}

int main()
{
	scanf("%d%d",&n,&m);
	S = n+1 , T = n+2;
	int L = 0 , R = 0;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&x[i],&y[i],&c1[i],&c2[i]),
		L = max(L , min(c1[i],c2[i])),
		R = max(R , max(c1[i],c2[i]));
		if(c1[i] > c2[i]) swap(c1[i] , c2[i]) , swap(x[i],y[i]);
		in[x[i]] -- , in[y[i]] ++ ;
	}
	int mid;
	for(;L<R;)
	{
		mid = (L+R) >> 1;
		if(check(mid)) 
			R = mid;
		else 
			L = mid + 1;
	}
	if(!check(L)) puts("NIE");
	else printf("%d\n",L);
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/88420639