题意:有一串项链断了,然后只找到了原来一部分的珠子,每个珠子两端有颜色,问剩下的珠子能够拼成一串完整的项链,相邻珠子的两端颜色必须相同。
分析:这是已到典型的欧拉回路的题,判断是否存在欧拉回路之后,直接dfs找到路径输出。
自己写的dfs不知道为什么错了,修改为fleury版后A了~~。
AC代码:
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 55;
const int maxm = 1005;
struct edge{
int v;
int No;//边的编号
edge(int _v, int _No){
v = _v; No = _No;
}
};
struct UFset{
int p[maxn];
int Find(int x){return p[x] >= 0 ? p[x] = Find(p[x]) : x;}
void Union(int r1, int r2){
r1 = Find(r1);
r2 = Find(r2);
int t = p[r1] + p[r2];
if(p[r1] < p[r2]){
p[r2] = r1;
p[r1] = t;
}
else{
p[r1] = r2;
p[r2] = t;
}
}
void Clear(){
for(int i = 0; i < maxn; i++){
p[i] = -1;
}
}
};
int m;//边的个数
vector<edge> list[maxn];//邻接链表
bool flag[maxn];//判断某种颜色是否出现过
bool vis[maxm];//for dfs 对边判重
UFset t;//并查集判连通
int start;//起点
bool ok;//判断dfs是否找到路径
void input(){
scanf("%d",&m);
for(int i = 0; i < maxn; i++){
list[i].clear(); flag[i] = false;
}
t.Clear();
int u,v;
for(int i = 0; i < m; i++){
scanf("%d%d",&u,&v);
list[u].push_back(edge(v,i));
list[v].push_back(edge(u,i));
flag[u] = true; flag[v] = true;
if(t.Find(u) != t.Find(v))
t.Union(u,v);
vis[i] = false;
}
}
bool is_euler(){
//判连通
start = -1;
for(int i = 0; i < maxn; i++){
if(!flag[i]) continue;//该颜色没有出现
if(start == -1) start = i;
if(t.Find(start) != t.Find(i))
return false;
//有奇度顶点
if(list[i].size() & 1) return false;
}
return true;
}
//正确写法
void dfs(int d, int s){
for(int i = 0; i < list[s].size(); i++){
int v = list[s][i].v;
int No = list[s][i].No;//边的编号
if(!vis[No]){
vis[No] = true;
dfs(d+1,v);
printf("%d %d\n",v,s);
}
if(ok) return;
}
}
void solve(){
dfs(0,start);
}
int main(){
int t;
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
scanf("%d",&t);
for(int i = 1; i <= t; i++){
input();
printf("Case #%d\n",i);
if(is_euler()) solve();
else puts("some beads may be lost");
if(i != t) puts("");
}
return 0;
}
错误代码:
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 55;
const int maxm = 1005;
struct edge{
int v;
int No;//边的编号
edge(int _v, int _No){
v = _v; No = _No;
}
};
struct UFset{
int p[maxn];
int Find(int x){return p[x] >= 0 ? p[x] = Find(p[x]) : x;}
void Union(int r1, int r2){
r1 = Find(r1);
r2 = Find(r2);
int t = p[r1] + p[r2];
if(p[r1] < p[r2]){
p[r2] = r1;
p[r1] = t;
}
else{
p[r1] = r2;
p[r2] = t;
}
}
void Clear(){
for(int i = 0; i < maxn; i++){
p[i] = -1;
}
}
};
struct node{//存储结果
int u,v;
};
int m;//边的个数
vector<edge> list[maxn];//邻接链表
bool flag[maxn];//判断某种颜色是否出现过
bool vis[maxm];//for dfs 对边判重
UFset t;//并查集判连通
int start;//起点
bool ok;//判断dfs是否找到路径
node ans[maxm];//结果
void input(){
scanf("%d",&m);
for(int i = 0; i < maxn; i++){
list[i].clear(); flag[i] = false;
}
t.Clear();
int u,v;
for(int i = 0; i < m; i++){
scanf("%d%d",&u,&v);
list[u].push_back(edge(v,i));
list[v].push_back(edge(u,i));
flag[u] = true; flag[v] = true;
if(t.Find(u) != t.Find(v))
t.Union(u,v);
vis[i] = false;
}
}
bool is_euler(){
//判连通
start = -1;
for(int i = 0; i < maxn; i++){
if(!flag[i]) continue;
if(start == -1) start = i;
if(t.Find(start) != t.Find(i))
return false;
//有奇度顶点
if(list[i].size() & 1) return false;
}
return true;
}
//错误写法
void dfs(int d, int s){
if(d == m){
ok = true; return;
}
for(int i = 0; i < list[s].size(); i++){
int v = list[s][i].v;
int No = list[s][i].No;//边的编号
if(!vis[No]){
vis[No] = true;
ans[d].u = s;
ans[d].v = v;
dfs(d+1,v);
vis[No] = false;
}
if(ok) return;
}
}
void solve(){
dfs(0,start);
for(int i = 0; i < m; i++){
printf("%d %d\n",ans[i].u,ans[i].v);
}
}
int main(){
int t;
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
scanf("%d",&t);
for(int i = 1; i <= t; i++){
input();
printf("Case #%d\n",i);
if(is_euler()) solve();
else puts("some beads may be lost");
if(i != t) puts("");
}
return 0;
}