sgu156:Strange Graph

题目描述


让我们想象一个无向图G=<V,E>.如果边(u,v)在边集E中,那么我们就说两个顶点u和v是邻接点.在这种情况下,我们也说u是v的一个邻接点且v是u的一个邻接点.我们用N(v)表示点v的邻接点集
合.我们知道v的邻接点数目也叫作这个点的度,用deg v表示.
我们说图G是奇怪的如果它是连通的且对于它的每一个点满足如下条件:
1.点v的度deg v>=2(表明v的邻接点至少有两个)
2.如果点v的度deg v=2,那么它的两个邻接点之间没有边相连
3.如果点v的度deg v>2,那么在它的邻接点集合N(v)中存在点u满足:
(a)点u的度deg u=2
(b)集合N(v)中除顶点u外任意两个不同的点是相邻的,即(w1,w2)这条边存在于边集E中.
现在给你某个这样的图,在里面找出一条哈密尔顿回路,一条哈密尔顿回路就是一条回路,这条回路经过图G中的每一点,且只经过一次.
输入


输入文件的第一行包含两个整数N和M——N为图G中定点的数目,M为图G中边的数目
(3<=N<=10000,M<=100000).接下来为2M个整数(每相邻两个点为一对)——每对数代表一条边的两个顶点(顶点被编号为1-N).输入数据保证每条边仅出现一次,且没有这样的环(边的两端点相同).
输出


如果在图G中没有哈密尔顿回路,则在输出文件的第一行输出-1.如果存在,则输出N个数——即在图G中找到的哈密尔顿回路的顶点序列(注意:最后一个点必须与第一个点相连).
如果有多种解,则输出任意一种即可.
Sample input #1


4 4
1 2 2 3 3 4 4 1
Sample input #2


9 12
1 2 2 3 3 1 1 4 2 5 3 6
4 7 5 8 6 9 7 8 8 9 9 7
Sample output #1


1 2 3 4
Sample output #2


-1


分析:
根据题意,很明显由条件3(b)我们可得一个deg>2的点与它所连的除deg=2的点可构成一个可两两相邻的连通分量,由此我们可以将其缩点。
然而求解哈密尔顿回路在此可以转换成在新图中求解欧拉回路,因为根据3(b),两个连通分量之间只可能由deg=2的一些点连接,且每个连通分量中的点都唯一对应一个deg=2的结点。
也就是说在新图中每走过一条边,就是走过了一个点,得证。
细节注意下哈,这题还是不难写的。
#include <cstdio>
#include <cstdlib>
using namespace std;
const int MAXN = 10005, MAXM = 100005;
int n, m;
struct edge
{
	int node;
	edge *nxt;	
}*e[MAXN] = {NULL}, *t[MAXN] = {NULL};
int deg[MAXN] = {0}, _deg[MAXN] = {0};
int col[MAXN] = {0}, top = 0;
int vis[MAXN] = {0}, s = 0;
bool hash[MAXN] = {0};

void add(int u, int v)
{
	edge *tmp;
	tmp	= (edge *)malloc(sizeof(edge));
	tmp->node = v;
	tmp->nxt = NULL;
	if(e[u] == NULL)
		e[u] = t[u] = tmp;
	else
	{
		t[u]->nxt = tmp;
		t[u] = tmp;	
	}
}

void dfs(int cur, int src)
{
	hash[cur] = true;
	for(edge *i = e[cur]; i != NULL; i = i->nxt)
		if(!hash[i->node])
		{
			int to = i->node;
			if(src && col[cur] == col[to])
				dfs(to, 0);
			else if((!src && col[cur] != col[to]) || deg[cur] == 2)
				dfs(to, 1);
		}
	vis[++s] = cur;
}

int main()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; ++i)
	{
		int x, y;
		scanf("%d%d", &x, &y);
		add(x, y);add(y, x);	
		deg[x]++;deg[y]++;
	}
	for(int i = 1; i <= n; ++i)
		if(deg[i] > 2 && !col[i])
		{
			++top;
			col[i] = top;
			for(edge *j = e[i]; j != NULL; j = j->nxt)
				if(deg[j->node] > 2)
					col[j->node] = top;
		}
		else if(deg[i] == 2)
			col[i] = ++top;
	for(int i = n; i >= 1; --i)
		if(deg[i]&1)//因为一个点的deg就代表了这个分量的deg
		{
			puts("-1");
			return 0;	
		}
	dfs(1, 0);
	for(int i = 1; i <= s; ++i)
		printf("%d ", vis[i]);
	
	return 0;	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值