sgu-101 Domino 欧拉路径

摘自nocow

描述

多米诺骨牌,一种用小的方的木块或其他材料,每个都被一些点在面上标记,这些木块通常被称为骨牌。每个骨牌的面都被一条线分成两个方形,两边各有一定点数。

N个多米诺骨牌,每个骨牌左右两侧分别有一个0~6的整数(骨牌可以旋转以调换其左右两数),求一种把这些骨牌从左到右排列的方案,使得所有相邻的两数字相等(即左边骨牌右侧的数字等于右边骨牌左侧的数字)。

输入

第一行是一个整数N(1 ≤ N ≤ 100),表示骨牌的数量。接下来的N行描述每块骨牌,每块左右两边有不同的点数。

输出

如果无法安排,输出“No solution”。如果可能,输出任何一种,每行有一个数字,和“+”或“-”,前者代表不旋转,后者代表旋转。

样例输入

5

1 2

2 4

2 4

6 4

2 1

样例输出

2 -

5 +

1 +

3 +

4 -


解题思路:

不难发现,如果把0~6当作顶点,则每个多米诺骨牌就相当于一条边,比如有1,2两个数字的多米诺骨牌就可以连一条1-2和一条2-1的有向边,然后在边上存上骨牌的编号和正反即可构成一张图,接着做欧拉路径就行了

那么如何做欧拉路径呢?首先对于一个有向图,有欧拉路径无向图要求度为奇数的点的个数只能为0或2(显然我上面的构图法可以看做无向图,因为每一个骨牌都双向连了边,可以看做无向图判断,具体如何判断请自己考虑)可以参考网友博客http://blog.chinaunix.net/uid-26380419-id-3164913.html

然后就是求欧拉路径了,具体求法上面网友博客中很详细,请读者自己阅读吧。

(ps:这道题好像有点坑,因为可能会出现一个骨牌两面的数字一样,这样要特判,请自己考虑)


//本人是淳朴的C党

#include <stdio.h>
#include <math.h>

int n;
int a[102][4]={0};
int bian[8][8][102]={0};//存下的是骨牌的标号,如果是正面就存正的,否则乘以-1在存入数组
int f=0;
int num[8]={0};
int t[8]={0};
int sum=0;
int k[8][8]={0};


void done(int o)
{
	int i,j,p;
	for(i=0;i<=6;i++)
	{
		if(bian[o][i][0]-k[o][i]>0)
		{
			k[o][i]++;
			k[i][o]++;
			j=k[o][i];
			done(i);
			if(bian[o][i][j]>0)
				p=bian[o][i][j];
			else p=-bian[o][i][j];
			printf("%d ",p);
			if(bian[o][i][j]>0)
				printf("-\n");
			else printf("+\n");
		}
	}
	return;
}


int main()
{
	int i,j;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i][1],&a[i][2]);
		num[a[i][1]]++;
		num[a[i][2]]++;
		bian[a[i][1]][a[i][2]][++bian[a[i][1]][a[i][2]][0]]=i;
		bian[a[i][2]][a[i][1]][++bian[a[i][2]][a[i][1]][0]]=-i;
		if(a[i][1]==a[i][2])
			t[a[i][1]]+=2;
	}
	for(i=0;i<=6;i++)
		if(num[i]>0)
			f++;
	if(f==1)
	{
		for(i=1;i<=n;i++)
			printf("%d +\n",i);
		return 0;
	}
	for(i=0;i<=6;i++)
	{
		if(num[i]==0)
			continue;
		if(num[i]-t[i]==0)
		{
			printf("No solution\n");
			return 0;
		}
		if((num[i]-t[i])&1)
			sum++;
	}
	if(sum!=2 && sum!=0)
	{
		printf("No solution\n");
		return 0;
	}
	if(sum==2)
	{
		for(i=0;i<=6;i++)
		{
			if((num[i]-t[i])&1)
			{
				done(i);
				break;
			}
		}
	}
	else
	{
		for(i=0;i<=6;i++)
		{
			if(num[i]>0)
			{
				done(i);
				break;
			}
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值