题意:给定n个珠子,每个珠子有一左一右两个颜色,颜色编号为1~50。求给定的珠子是否能串成一个项链,珠子相连连接的地方颜色要求一样。能串成一个项链则输出一种项链的顺序。
分析:我们如果将一颗珠子的两个颜色直接看成是一条无向边的话,那么这个题就是要求是否存在一条欧拉回路啦。判无向图是否为欧拉回路:1,图要求连通。2,所有点的度数要求是偶数。这个题的数据没有不连通的,所有我们直接判条件2即可。但是重点是输出一种欧拉回路的路径,这个我想了很久都感觉不好处理,本来我是想对于每一个点都留一条边来走最后一步以避免成环后其他点遍历不到,但是这样处理会有很多复杂的细节需要处理。后来看别人题解学习了一种只需要dfs即可的方法,我们dfs的时候不要顺序输出而是换成逆序输出(见代码),这样处理的话就像是弄一个栈每次找到一条边不急着输出而是先压进栈,到后面找到匹配的边在慢慢弹出栈。我们可以想象如果我们构造一个括号匹配,我们不是从外层的括号开始确定而是从内到外一层一层扩大。还不理解的话看代码自己脑子里模拟一下吧。
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<vector>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=1010;
const int mod=1000000007;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const int INF=1000000010;
const ll MAX=1ll<<55;
const double eps=1e-5;
const double inf=~0u>>1;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned int uint;
typedef unsigned long long ull;
int d[55],ma[55][55];
void euler(int u) {
for (int v=1;v<=50;v++)
if (ma[u][v]) {
ma[u][v]--;ma[v][u]--;
euler(v);printf("%d %d\n", v, u);
}
}
int main()
{
int a,b,i,n,t,ca,bo;
scanf("%d", &t);
for (ca=1;ca<=t;ca++) {
scanf("%d", &n);
memset(d,0,sizeof(d));
memset(ma,0,sizeof(ma));
for (i=1;i<=n;i++) {
scanf("%d%d", &a, &b);
d[a]++;d[b]++;
ma[a][b]++;ma[b][a]++;
}
for (bo=1,i=1;i<=50;i++)
if (d[i]&1) bo=0;
printf("Case #%d\n", ca);
if (bo) {
for (i=1;i<=50;i++) euler(i);
} else printf("some beads may be lost\n");
if (ca!=t) printf("\n");
}
return 0;
}