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;
}