Wannafly交流赛1: C. 腰带图(瞎搞)

链接:https://www.nowcoder.com/acm/contest/69/C
来源:牛客网

题目描述

一个n个点m条边的无向图,它若满足以下性质,我们就称它为腰带图:

1.n为>=6的偶数。
2.这个图恰有3/2*n条边。
3.存在所有点的一个排列p 0,p 1,...,p n-1,使得对于所有满足0<=i<n/2的整数i:

(1)点pi和点p(i+1) mod (n/2)间有边相邻。

(2)点pi+n/2和点pn/2+(i+1) mod (n/2)间有边相邻。

(3)点pi和点pi+n/2间有边相邻。

注:x mod y为x除以y的余数。

现在给你一个无向图,请判断他是否是腰带图。

输入描述:

输入的第一行有一个正整数T,代表询问数。

每个询问各占1+m行,当中的第1行有两个正整数n,m分别代表点数和边数,接下来m行当中的第i行包含两个整数xi,yi,代表点xi和点yi间有边相连。

输出描述:

  
  
每个询问的回答占1行,若此图不是腰带图,该行里只包含一个整数-1;
若是腰带图,则输出n个数p 0,p1,...,p n-1,其为任一个能证明此图是腰带图的0~n-1的排列。(意思就是题面里提到的该有的边都存在。)


把题目中的要求和样例画出来,你会发现腰带图中有两个主环,每个环上刚好n/2个点,并且这两个环n/2对点一一对应,8个点的腰带图具体如下:(0123在一个主环上,4567在另一个主环上)



n只有200,感觉可以瞎搞,下面给出一个O(3²n)的方法

①首先每个点的度数都必须为3,否则输出-1

②固定0号点(即p0一定为0),然后暴力与0号点相连的3个点,确定与0对应的点x

(x和0在不同的主环上,他们之间有一条边,即上图中的'4'号点)

③确定了图中的'0'和'4'后,就找下面两个点'1'和'5',找到之后接着找'2'和'6'……直到最后两个点'3'和'7'

这个很好办,它们必须没有被标记过并且有条边连接着他们,中间某个时候找不到就说明不行

④确定最后两个点是否和最一开始的两个固定的点相连,如果相连就OK,说明这是其中一组解

⑤如果固定与0号点相连的3个点都不能找到解,就输出-1


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct
{
	int x;
	int y;
}Res;
Res s[305];
int road[205][5], cnt[205], ans[205];
int Find(int x, int y)
{
	int i;
	for(i=1;i<=3;i++)
	{
		if(road[x][i]==y)
			return 1;
	}
	return 0;
}
int main(void)
{
	int T, i, j, k, n, m, x, y, x2, y2, p, q;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d%d", &n, &m);
		memset(cnt, 0, sizeof(cnt));
		for(i=1;i<=m;i++)
			scanf("%d%d", &s[i].x, &s[i].y);
		for(i=1;i<=m;i++)
		{
			x = s[i].x+1, y = s[i].y+1;
			road[x][++cnt[x]] = y;
			road[y][++cnt[y]] = x;
			if(cnt[x]>=4 || cnt[y]>=4)
				break;
		}
		if(i<=m)
		{
			printf("-1\n");
			continue;
		}
		memset(ans, -1, sizeof(ans));
		for(i=1;i<=3;i++)
		{
			x = 1, y = road[1][i];
			ans[x] = 0, ans[y] = n/2;
			for(j=1;j<=3;j++)
			{
				for(k=1;k<=3;k++)
				{
					x2 = road[x][j], y2 = road[y][k];
					if(Find(x2, y2) && ans[x2]==-1 && ans[y2]==-1)
						goto loop;
				}
			}
			continue;
			loop:;
			for(j=2;j<=n/2-1;j++)
			{
				x = x2, y = y2;
				ans[x] = j-1, ans[y] = j-1+n/2;
				for(p=1;p<=3;p++)
				{
					for(q=1;q<=3;q++)
					{
						x2 = road[x][p], y2 = road[y][q];
						if(Find(x2, y2) && ans[x2]==-1 && ans[y2]==-1)
							goto loop2;
					}
				}
				break;
				loop2:;
			}
			if(j<=n/2-1)
			{
				memset(ans, -1, sizeof(ans));
				continue;
			}
			x = x2, y = y2;
			ans[x] = j-1, ans[y] = j-1+n/2;
			for(p=1;p<=3;p++)
			{
				for(q=1;q<=3;q++)
				{
					x2 = road[x][p], y2 = road[y][q];
					if(Find(x2, y2) && ans[x2]==0 && ans[y2]==n/2)
						goto loop3;
				}
			}
			memset(ans, -1, sizeof(ans));
			continue;
			loop3:;
			printf("0");
			for(j=1;j<=n-1;j++)
			{
				for(k=1;k<=n;k++)
				{
					if(ans[k]==j)
						printf(" %d", k-1);
				}
			}
			printf("\n");
			break;
		}
		if(i==4)
			printf("-1\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值