您的位置:首页 > 其它

zoj 1992 || poj 1637 Sightseeing Tour

2011-03-07 22:02 423 查看
混合图的欧拉回路。



以前没遇到过这种题,纠结啊。。。搜了下,发现是需要用最大流解的,隐约记得黑书上最大流有讲这个的,就去翻黑书了。



黑书提供了两种算法,第一种自己模拟了下,觉得有点看不懂,觉得它书有的地方没说清楚,而且我自己模拟的结果不对 = =。。。



第二种算法是网上大家经常用的,理解了下。



大致就是,先将无向边定向,就是比如1<->3,可以定它的方向为1->3,1的出度++,3的入度++即可。



读入的时候如果遇到无向边,把这条边加入待建的网络中,流量为1。读入完后,然后用出度减入度得到x,如果x为奇数,肯定不存在欧拉回路,如果没有奇数,就用最大流求解。



如果x大于0,则建一条s(源点)到当前点容量为x/2的边,如果x小于0,建一条从当前点到 t(汇点)容量为|x/2|的边。



然后求最大流,如果是满流(即s出的流==t入的流即可,s指的是建图的时候连接s的边的容量和)就满足欧拉回路。



这题我用递归的dinic做的,开始用并查集判连通了,嘻嘻,好不容易把邻接矩阵改成邻接表了,嘻嘻,我好伟大~~拉拉~~~



这题在zoj排第一了,哇咔咔咔~~~



#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <algorithm>
#define MAX 205
using namespace std;
int pre[MAX],n;
int ind[MAX],outd[MAX];
int lev[MAX];
typedef struct MAP{
    int cap,to;
	int next;
}MAP;
MAP node[3000];
int head[MAX];
int cou;
void init()
{
	cou = 2;
	memset(node,'/0',sizeof(node));
	memset(head,-1,sizeof(head));
	memset(ind,0,sizeof(ind));
	memset(outd,0,sizeof(outd));
	for(int i=1; i<=n; i++)
		pre[i] = i;
}
int find(int x)
{
	while( x != pre[x] )
		x = pre[x];
	return x;
}
void Union(int x,int y)
{
	int a = find(x);
	int b = find(y);
	if( a == b )
		return ;
	int p = min(a,b);
	pre[a] = pre[b] = pre[x] = pre[y] = p;
}
int check()
{
	for(int i=1; i<=n; i++)
		if( find(i) != 1 )
			return 0;
	return 1;
}
void Add(int u,int v,int cap)
{
     node[cou].to = v;
	 node[cou].cap = cap;
	 node[cou].next = head[u];
	 head[u] = cou++;
	 
	 node[cou].to = u;
	 node[cou].cap = 0;
	 node[cou].next = head[v];
	 head[v] = cou++;
}
queue<int> q;
int BFS(int s,int t)
{
	int p,u,v,cap;
	memset(lev,-1,sizeof(lev));
	q.push(s);
	lev[s] = 0;
	while( !q.empty() )
	{
		u = q.front();
		q.pop();
		p = head[u];
		while( p != -1 )
		{
			v = node[p].to;
			cap = node[p].cap;
			if( cap > 0 && lev[v] == -1 )
			{
				lev[v] = lev[u] + 1;
				q.push(v);
			}
			p = node[p].next;
		}
	}
	return lev[t] != -1;
}
int Dinic(int k,int sum,int s,int t)
{
	int i,a,os;
	if( k == t )
		return sum;
	os = sum;
	int p = head[k];
	while( p != -1 && sum )
	{
		int to = node[p].to;
		int cap = node[p].cap;
		if( lev[to] == lev[k] + 1 && cap > 0 )
		{
			a = Dinic(to,min(sum,cap),s,t);
			node[p^1].cap += a;
			node[p].cap -= a;
			sum -= a;
		}
		p = node[p].next;
	}
	return os - sum;
}
int main()
{
	int m,from,to,s;
	int ncases;
	scanf("%d",&ncases);
	while( ncases-- )
	{
		scanf("%d%d",&n,&m);
		init();
		while( m-- )
		{
			scanf("%d%d%d",&from,&to,&s);
			if( from == to )
				continue;
			ind[to]++;
			outd[from]++;
			Union(from,to);
			if( s != 1 )
				Add(from,to,1);
		}
		if( !check() )
		{
			printf("impossible/n");
			continue;
		}
		int flag = 1;
		int sum = 0;
		for(int i=1; i<=n; i++)
		{
			outd[i] -= ind[i];
			if( outd[i] % 2 == 1 )
			{
				flag = 0;
				break;
			}
			outd[i] /= 2;
			if( outd[i] > 0 )
			{
				Add(0,i,outd[i]);
				sum += outd[i];
			}
			else
				Add(i,n+1,-outd[i]);
		}
		if( !flag )
		{
			printf("impossible/n");
			continue;
		}
		int ans = 0;
		while( BFS(0,n+1) )
			ans += Dinic(0,INT_MAX,0,n+1);
		if( ans == sum )
			printf("possible/n");
		else
			printf("impossible/n");
	}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: