题目大意
给定你n张骨牌,每张牌左右两端有一个数字,每张牌的左右两端数字可以颠倒,找出一种摆放骨牌的顺序,使得相邻骨牌的两端数字相同(最左边骨牌的最左端和最右边骨牌的最右端可以不管)。
解题思路
这是个很普通无向图欧拉回路,但是要注意判断这个图是否在一个连通分量里面!
输出No solution的条件有两个
1. 如果不满足欧拉回路的性质就输出
2. 如果不在一个连通分量
对应于第一个就是判断每个节点度,如果是0个或者两个就是欧拉回路
对于第二个来讲如果有节点没有访问过,就代表有不止一个连通分量
然后如果是有奇数度就选从奇数度中的任意一个出发,如果没有奇数度就随便选一个度不为0的 节点出发
AC代码
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 250;
int head[MAXN],IN[MAXN];
int start,path[MAXN],tot,edgeCnt;
bool vis[MAXN];
struct Edge{
int v,id,nxt;
}E[MAXN<<1];
void initEdge()
{
edgeCnt = 0;
tot = 0;
memset(head,-1,sizeof head);
memset(IN,0,sizeof IN);
memset(vis,false,sizeof vis);
}
void addEdge(int u,int v,int id)
{
E[edgeCnt].v = v;
E[edgeCnt].id = id;
E[edgeCnt].nxt = head[u];
head[u] = edgeCnt++;
}
bool check()
{
int count = 0;
for(int i = 0; i <= 6; i++)
if(IN[i]&1)
{
count++;
start = i;
}
if(count == 1||count > 2) return false;
if(count == 2) return true;
for(int i = 0; i <= 6; i++)
if(IN[i] > 0)
{
start = i;
break;
}
return true;
}
void Fleury(int u)
{
for(int i=head[u];~i;i=E[i].nxt)
{
int v = E[i].v;
int id = E[i].id;
if(!vis[(int)abs(id)])
{
//printf("[%d,%d]\n",v,id);
vis[(int)abs(id)] = true;
Fleury(v);
path[tot++] = id;
}
}
}
int main()
{
int M;
int u,v;
while(~scanf("%d",&M))
{
initEdge();
for(int i=1;i<=M;i++)
{
scanf("%d%d",&u,&v);
addEdge(u,v,i);
addEdge(v,u,-i);
IN[u]++;
IN[v]++;
}
if(!check())
{
printf("No solution\n");
continue;
}
//printf("[%d]",start);
Fleury(start);
for(int i=1;i<=M;i++)
if(!vis[i]){
printf("No solution\n");
goto jumpEnd;
}
for(int i=tot-1;i>=0;i--)
if(path[i]>0) printf("%d +\n",path[i]);
else printf("%d -\n",-path[i]);
jumpEnd:;
}
return 0;
}