2018.10.09【BZOJ2095】【POI2010】MOS-Bridges(欧拉回路)(二分答案)(最大流)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/82988337

DarkBZOJ传送门


解析:

这绝对是我做过的最扯的欧拉回路的题了,明明标签是欧拉回路,可是怎么是一道网络流加二分答案啊?

思路:

首先,看到要求最大值最小,多半是个二分,然而。。。
二分之后验证什么?
好吧,看题目应该知道是要求欧拉回路。

那直接爆搜求欧拉回路?

(和谐) 想都知道是不可能的,怎么都能卡掉。

那怎么验证?

先想一想如何验证一般图是否存在欧拉回路:

1.无向图:一笔画问题相信大家都有所了解,只要不存在度数为奇数的节点就一定存在欧拉回路;
1.有向图:这个稍微有一点麻烦,但是结论说出来十分显然。一个有向图存在欧拉回路,当且仅当该图联通且所有节点入度等于出度。

读过刘汝佳……小蓝还是小紫来着,算了不重要……的读者可能见过一道题,直接求混合图的欧拉回路。

其实解法就是网络流。

我们只需要规定一些无向边的方向,使得这张图满足有向图存在欧拉回路的条件就行了。

至于怎么规定,总之要先将每一条边都有一个方向能够加入这张图才行。
我们先将正向反向都能够走的边加入原图,反正都是无向图,我们直接假设走的是风力小的方向,反正之后有办法处理。

首先这时候每个点的总度数必须是偶数,一旦是奇数肯定无解,然后我们将它需要将入边变向还是出边变向,分别向源汇连边,容量为出入度只差的绝对值的一半,表示我们需要将这条边的出入度调整多少才能相等。

这时候有向边就不用加进流网络的图里面了。

因为我们这时候是在调整无向边的方向,通过能否调整出合法情况来判断是否有解。合法的情况就是源汇都流满,说明差的流量能够被补上。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const 

inline ll getint(){
	re ll num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

cs int N=1003;
cs int M=4003;
cs int INF=0x3f3f3f3f;
int n,m;
int last[N],nxt[1000005],to[1000005],ecnt;
int cap[1000005];
inline void addedge(int u,int v,int val){
	nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,cap[ecnt]=val;
	nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,cap[ecnt]=0;
}

int u[M>>1],v[M>>1],c[M>>1],d[M>>1];
int S=0,T=1001;
int minn=INF,maxn=0;
int du[N],tot;

int lev[N],cur[N];
inline bool BFS(){
	memset(lev,-1,sizeof lev);
	queue<int> q;
	q.push(S);lev[S]=0;cur[S]=last[S];
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
			if(cap[e]&&lev[v]==-1){
				lev[v]=lev[u]+1;
				if(v==T)return true;
				cur[v]=last[v];
				q.push(v);
			}
		}
	}return false;
}

inline int Dinic(cs int &u,cs int &flow){
	if(u==T)return flow;
	int ans=0;
	for(int &e=cur[u],v=to[e];e;v=to[e=nxt[e]]){
		if(cap[e]&&lev[v]>lev[u]){
			int delta=Dinic(v,min(flow-ans,cap[e]));
			if(delta){
				ans+=delta;
				cap[e]-=delta;
				cap[e^1]+=delta;
				if(ans==flow)return ans;
			}
		}
	}
	return ans;
}

inline int maxflow(){
	int ans=0;
	while(BFS())ans+=Dinic(S,INF);
	return ans;
}

inline void build(int mid){
	memset(last,0,sizeof last);
	memset(du,0,sizeof du);
	ecnt=1;
	tot=0;
	for(int re i=1;i<=m;++i){
		if(c[i]<=mid)--du[u[i]],++du[v[i]];
		if(d[i]<=mid)addedge(v[i],u[i],1);
	}
	for(int re i=1;i<=n;++i)
	if(du[i]>0)tot+=du[i]>>1,addedge(S,i,du[i]>>1);
	else if(du[i]<0)addedge(i,T,(-du[i])>>1);
}

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

signed main(){
	n=getint();
	m=getint();
	for(int re i=1;i<=m;++i){
		u[i]=getint(),v[i]=getint(),c[i]=getint(),d[i]=getint();
		if(c[i]>d[i])swap(c[i],d[i]),swap(u[i],v[i]);
		minn=min(c[i],minn);
		maxn=max(d[i],maxn);
	}
	int l=minn,r=maxn;
	while(l<=r){
		int mid=(l+r)>>1;
		if(check(mid))r=mid-1;
		else l=mid+1;
	}
	if(l==maxn+1)puts("NIE");
	else cout<<l;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/82988337
今日推荐