sgu101

SGU101 Domino

题目大意:

描述

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

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 -

 

暴力的DFS会超时(这是不用解释的)

显然使用的是欧拉路径求解。

若不知道欧拉路径,请自行百度(一笔画问题)(提供参考http://blog.csdn.net/prime_min/article/details/40686563)

 

具体想法:1.建立欧拉路径图。

2.根据每个点的性质判断是否有解(若奇点个数为0或2,则有解,否则无解)

若有解:

3.奇点个数为0,则从任意一个存在的点开始遍历整个图。

4.奇点个数为2,则从奇点开始遍历整个图。

5.若遍历成功,则记录路径,按题目要求输出。

   若遍历不成功,则无解。

 

注意事项:

1.看清楚到底哪一面是正面,哪一面是负面。

2.奇点个数为0时,要从一个存在的点开始(不存在的点不能遍历,原因自行脑补)。

3.值得注意的一点,在输出时一张domino牌只能用一次,如果搞错会在test 5之前Wrong Answer

 

下面附上我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct d
{
  int up;
  int down;
}domino[101],ans[101];
int oula[7][7];
int point[7];
int start,num,n;
int check[101];
int total,pass;
void search(int i)   //遍历整个欧拉路径
{
  int j;
  for (j=0;j<=6;j++)
    if (oula[i][j])
      {
   	  oula[i][j]--;
   	  oula[j][i]--;
   	  search(j);
   	  ans[++total].up=i;
   	  ans[total].down=j;
      }
  return ;
}
void init()
{
  int i,j,k;
  scanf("%d",&n);
  for (i=1;i<=n;i++)   //输入和构建欧拉图
    {
    scanf("%d%d",&domino[i].up,&domino[i].down);
    oula[domino[i].up][domino[i].down]++;
    oula[domino[i].down][domino[i].up]++;
    point[domino[i].up]++;
    point[domino[i].down]++;
    }
  for (i=6;i>=0;i--)  //寻找奇点和个数
    if (point[i]&1)
      { num++; start=i; }
  if (num==0) //若奇点个数为0,找第一个存在的点作为起始点
    for (;start<7 && point[start]==0;start++);
  if (num!=2 && num!=0)  //根据奇点个数判断是否有解
    {
    printf("No solution");
    return ;
	}
  else
    {
    search(start);
    if (total<n)  //根据便利状况判断是否有解
      {
      printf("No solution");
      return ;
	  }
    for (i=1;i<=total;i++)  //根据路径输出答案
      for (j=1;j<=n;j++)
        if (!check[j])
          if (domino[j].up==ans[i].up && domino[j].down==ans[i].down)
            {
            check[j]=1;
		    printf("%d -\n",j);
		    break;
            }
          else if (domino[j].up==ans[i].down && domino[j].down==ans[i].up)
            {
			check[j]=1;
			printf("%d +\n",j);
			break;
			}
    }
  return ;
}
int main()
{
  init();
  return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值