题意: 给出n块多米诺骨牌,每块骨牌的左右端点有标号(0~6),现要求把给定的骨牌排成一排,要求相邻骨牌的相邻端点标号相等。按顺序输出摆放好的骨牌和它们是否翻转过。
解法: 以0~6为点,骨牌为边,找欧拉通路。先判图的连通性,再判是否存在欧拉通路,存在就DFS一遍输出答案。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define clr(a,b) memset(a,b,sizeof(a))
typedef long long lld;
const int INF = ~0u>>1;
int n;
const int MAXN = 110;
struct Edge {
int v, w, next;
int us;
}g[MAXN<<1];
int head[7],tot;
int ds[7];
int fa[7];
int ans[MAXN],pa;
void dfs(int u) {
for(int p=head[u]; ~p; p=g[p].next) {
if(g[p].us) continue;
g[p].us = g[p^1].us = 1;
dfs(g[p].v);
ans[pa++] = g[p].w;
}
}
int Find(int x) {
return fa[x] = (fa[x] == x) ? x : Find(fa[x]);
}
void merge(int a, int b) {
a = Find(a); b = Find(b);
if(a == b) return ;
fa[a] = b;
}
void add_edge(int u, int v, int id) {
g[tot].v = v; g[tot].w = id;
g[tot].next = head[u]; head[u] = tot ++;
g[tot].v = u; g[tot].w = -id;
g[tot].next = head[v]; head[v] = tot ++;
}
int main() {
scanf("%d", &n);
clr(head, -1);
REP(i,0,7) fa[i] = i;
int l,r;
REP(i,1,n+1) {
scanf("%d%d", &l, &r);
ds[l] ++;
ds[r] ++;
merge(l,r);
add_edge(l,r,i);
}
int od = 0, ok = 1;
int first = 1,kkk;
REP(i,0,7) {
if(ds[i]&1) od ++;
if(ds[i] != 0) {
if(first) {
kkk = Find(i); first = 0;
}
else {
if(Find(i) != kkk) ok = 0;
}
}
}
if(ok == 0 || od!=0 && od!=2) printf("No solution\n");
else {
if(od == 0) dfs(r);
else {
int i;
for(i=0; i<=6; i++) if(ds[i]&1) break;
dfs(i);
}
for(int i=pa-1; i>=0; i--) {
int x = abs(ans[i]);
printf("%d %c\n", x, x == ans[i] ? '+' : '-');
}
}
return 0;
}