[POJ1637] Sightseeing tour

POJ1637 观光旅行

题目链接 : http://poj.org/problem?id=1637

Description:
给定一个 n 个节点, m 条边的混合图,有一些边是有向边,有一些边是无向边。
请给无向边定向,使得最后的有向图存在经过所有边仅一次的回路。并给出方案。
其中 1 ≤ n ≤ 200, 1 ≤ m ≤ 2000 。

模型:混合图欧拉回路问题 - 网络流

1.定义 : 混合欧拉回路问题,即在一张包含有向边和无向边的混合图中求欧拉回路

2.有向图欧拉回路判断:所有顶点的入度与出度之差为0。

3.混合图欧拉回路 :
首先,我们把无向边设定为任意一个方向
虽然不一定是欧拉回路
但是我们可以进行反悔操作

如果进行反悔操作
对于跟这条边连的点
入度++,出度--
或者
入度--,出度++

所以改变一条边的方向后
一个点入度/出度之差会+2或-2

所以在我们任意连边后,如果一个的(入度-出度)为奇数
那么它无论如何也不能变成出入度之差为0的点
于是impossible

然后接下来就要用到网络流了
我们不妨设一个点的入度为--\(in[v]\)出度为--\(ou[v]\)
对于一个点v
有一个非常重要的量\(tmp_v=ou[v]-in[v]\)

我们先用原始人的思维想一下
我们如果改变一条边 u -> v 的方向
那么\(tmp_u-=2 \&\& tmp_v+=2\)
所以我们可以超级暴力地枚举更换哪一条边的方向
就这么加加减减
直到所有的$ in[i]=ou[i]=0 $

然后可以考虑用网络流优化
引用自 https://blog.csdn.net/chenzhenyu123456/article/details/48302459

我们可以构建网络流模型,判断剩余度数能否完全分配。下面需要确定的是模型中边的方向.

假设我们定向原图中边<u, v>方向为u -> v。
1,当u的出度大于入度,才可能把多的出度分配给v,当做v的入度。这个度数能否成功分配可以用能否到达汇点sink来判定。

2,当u的出度小于入度,v是不可能把多的出度分配给u的,因为v->u没有边。这个时候我们必须要从source给点u分配度数。


这样建边方向就出来了,若确定无向边<u, v>方向为u -> v。

那么当点的in < out时,源点source向它建边,容量为差值的一半。当点的out > in时,它向汇点建边,容量为差值的一半。

建图:设置超级源点source,超级汇点sink。

1,对于边<u, v>,若它是无向的,我们人为定向,u向v建边,容量为1。当欧拉路径中是v -> u的,u多出的度数可以流到v。

2,若in[i] < out[i],则source向i建边,容量为正差值的一半;

3,若in[i] > out[i],则i向sink建边,容量为正差值的一半。

统计从source流入的流量sum,最后判断是否满流即可。
/*
一个并不能AC
但是把重要思想体现出来的代码
原谅我实在不想做POJ的题目QvQ
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>

#define rg register int
#define ll long long
#define RG register 
#define il inline

using namespace std;

il int gi() {
	rg x=0,o=0;RG char ch=getchar();
	while(ch!='-'&&(ch<'0'||'9'<ch)) ch=getchar();
	if(ch=='-') o=1,ch=getchar();
	while('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return o?-x:x;
}

#define N 501
#define M 20001
const int inf=214748364;

int s,t,n,m,Ans,sum;
int in[N],ou[N];

struct Edge { int to,nxt,w; } e[M];
int Ehead[N],Ecnt=2;
il void Eadd(int u,int v,int w) {
	e[Ecnt]=(Edge){v,Ehead[u],w};
	Ehead[u]=Ecnt++;
	e[Ecnt]=(Edge){u,Ehead[v],0};
	Ehead[v]=Ecnt++;
}

int lev[N],cur[M];
queue <int> Q;
il bool bfs() {
	while(!Q.empty()) Q.pop();
	memset(lev,-1,sizeof(lev));
	Q.push(s),lev[s]=0;
	while(!Q.empty()) {
		int u=Q.front(); 
		Q.pop();
		for(int v,i=Ehead[u]; i; i=e[i].nxt) {
			v=e[i].to;
			if(e[i].w<=0 || lev[v]>0) continue;
			lev[v]=lev[u]+1;
			Q.push(v);
		}
	}
	return lev[t]>0;
}
int dfs(int u,int f) {
	if(u==t || !f) return f;
	for(int &i=cur[u]; i; i=e[i].nxt) {
		int v=e[i].to,di=0;
		if(lev[v]!=lev[u]+1) continue;
		if(di=dfs(v,min(f,e[i].w))) {
			e[i].w-=di;
			e[i^1].w+=di;
			return di;
		}
	}
	return 0;
}
il void maxflow() {
	int di;
	while(bfs()) {
		for(int i=s; i<=t; ++i) cur[i]=Ehead[i];
		Ans+=dfs(s,inf);
	}
}

int main() {
	n=gi(),m=gi();
	s=0,t=n+1;
	for(int u,v,w,i=1;i<=m;++i) {
		u=gi(),v=gi(),w=gi();
		++in[v],++ou[u];
		if(!w) Eadd(u,v,1);
	}
	for(int tmp,i=1; i<=n; ++i) {
		tmp=abs(in[i]-ou[i]);
		if(tmp&1) {
			puts("Impossible");
			return 0;
		}
		tmp>>=1;
		if(in[i]<ou[i]) sum+=tmp, Eadd(s, i, tmp);
		else Eadd(i, t, tmp);
	}
	maxflow();
	Ans==sum?puts("possible"):puts("impossible");
	return 0;
}
posted @ 2018-04-12 16:40  TPLY  阅读(67)  评论(0编辑  收藏
free web counter
free web counter