101. 多米诺
每个测试点时间限制: 0.50 sec
每个测试点内存限制: 4096 KB
多米诺 ——一种用木头或者其他材料做的小方块进行的游戏,其中每个小方块面上通常标记点数或分数。这些小方块被称作骨牌,多米诺。有时用骨片,用人,甚至用卡片。
每个小块的表面被一条线分割成两部分,每一部分都写上了可能成对的号码。
在差不多所有的现代多米诺骨牌游戏中,比赛原则是要使两个标有相同或成对的号码的小方块首尾相接应。
——《大英百科全书》
给你一些多米诺骨牌,每块的两部分都标记上 0 到 6 的号码,你的任务是把这些骨牌排列在一条直线上,使得相邻骨牌的相邻部分有同样的号码。骨牌可以左右翻转。
输入
第一行包括一个整数 N (1 ≤ N ≤ 100) 表示骨牌总数。接下来 N 行描述每一块骨牌两部分的号码,每行两个 0 - 6 的数,用空格隔开。
输出
如果不存在这样的方案,输出 “No solution”。如果方案存在,输出任意一种符合要求的方案。输出方案时应该从左到右描述骨牌的排列,每行输出用空格隔开的一个整数和一个字符,分别表示骨牌的编号和是否翻转骨牌,(+表示不翻转,-表示翻转)。
样例输入
5
1 2
2 4
2 4
6 4
2 1
样例输出
2 -
5 +
1 +
3 +
4 -
================================华丽的分割线 ================================
要上学了,下午回来再发。 2011年6月4日 14时00分45秒
要注意到这个可以转换成为图,最开始我计划使用骨牌作为节点,但是发现数据处理太麻烦了,第一节点数目多,第二每添加一个新骨牌处理都可能是O(n^2)的数量级,所以一直没有动手(如果要写可能不一定需要O(n^2)的数量级处理输入数据,但是越简单越具有生命力,果断放弃。)。所以将0~6作为节点,每个骨牌就是一条边。
所以就转换成了已知7个节点和n条边,要将每条边都走一边,很明显是个欧拉路径。
PS: SGU的数据很变态的,数量大,考虑方面要周全。此题要考虑:是否联通图,是否存在欧拉路。
#include < stdlib.h >
int head[ 7 ];
int buff[ 201 ];
int * side = & buff[ 100 ];
int buff2[ 201 ];
int * next = & buff2[ 100 ];
int len;
int count[ 7 ];
int used[ 101 ];
void add( int x, int y)
{
int i;
i = ++ len;
side[i] = y;
next[i] = head[x];
head[x] = i;
side[ - i] = x;
next[ - i] = head[y];
head[y] = - i;
count[x] ++ , count[y] ++ ;
}
int ans[ 101 ];
int end;
void dfs( int k)
{
int i;
i = head[k];
while (i != 0 ){
if ( ! used[abs(i)]){
used[abs(i)] = 1 ;
dfs(side[i]);
ans[end ++ ] = i;
}
i = next[i];
}
}
int main( int argc, char ** argv)
{
int i;
int a, b;
int n, t, s;
scanf( " %d " , & n);
for (i = 0 ; i < n; i ++ ){
scanf( " %d%d " , & a, & b);
add(a, b);
}
t = 0 ;
for (i = 0 ; i <= 6 ; i ++ ){
if (count[i] & 1 ){
t ++ ;
s = i;
}
}
if (t > 2 ){
printf( " No solution\n " );
exit( 0 );
}
if (t == 0 ){
for (i = 0 ; i <= 6 ; i ++ ){
if (count[i] > 0 ){
s = i;
break ;
}
}
}
dfs(s);
for (i = 1 ; i <= n; i ++ ){
if ( ! used[i]){
printf( " No solution\n " );
exit( 0 );
}
}
for (i = end - 1 ; i >= 0 ; i -- ){
if (ans[i] > 0 ){
printf( " %d +\n " , ans[i]);
} else {
printf( " %d -\n " , - ans[i]);
}
}
return 0 ;
}