题目链接:
(https://cn.vjudge.net/problem/UVA-10054)
关于欧拉回路:
若图G中存在这样一条路径,使得它恰通过G中每条边一次,则称该路径为欧拉路径。若该路径是一个圈,则称为欧拉(Euler)回路。
无向图存在欧拉回路的充要条件:
一个无向图存在欧拉回路,当且仅当该图所有顶点度数都为偶数,且该图是连通图。
有向图存在欧拉回路的充要条件:
一个有向图存在欧拉回路,所有顶点的入度等于出度且该图是连通图。
这道题可以把每个珠子的两种颜色看做两个节点,两个节点之间连一条边。
关于打印路径问题,是一个dfs回溯,一定要逆序输出。
关于判断图的连通性:
用并查集实现,如果仅有一个联通块,那么这个图是联通的,也就是所有的节点都只有一个共同的根节点。
代码如下:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1000+5;
int G[maxn][maxn]; //保存边,每一组输入连一条变
int num[maxn]; //统计各个节点的入度出度
int node[maxn]; //并查集数组
int done[maxn]; //标记节点是否被遍历
//数据初始化
void init()
{
for(int i=0; i<=maxn; i++)
node[i]=i;
memset(num,0,sizeof(num));
memset(G,0,sizeof(G));
memset(done,0,sizeof(done));
}
//并查集找根节点
int finds(int x)
{
if(x==node[x])
return x;
return finds(node[x]);
}
//合并
void unit(int x,int y)
{
x=finds(x);
y=finds(y);
if(x==y)
return ;
node[x]=y;
}
//回溯输出打印答案,记住一定要逆序输出
void dfs(int u)
{
for(int i=1; i<=50; i++)
{
if(G[u][i])
{
G[u][i]--;
G[i][u]--;
dfs(i);
printf("%d %d\n",i,u);
}
}
return;
}
int main()
{
int T;
scanf("%d",&T);
int kase=0;
while(T--)
{
init();
int n;
scanf("%d",&n);
int Elem;
for(int i=0; i<n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
Elem=x;
G[x][y]++; //连边
G[y][x]++;
num[x]++; //统计入度出度
num[y]++;
done[x]=1; //该节点被遍历
done[y]=1;
unit(x,y);
}
int flag=1;
//是否存在奇度节点
for(int i=0; i<maxn; i++)
{
if(num[i]%2!=0)
flag=0;
}
//判断图的连通性,如果存在多个根节点,则不是一个联通块
for(int i=0; i<maxn; i++)
{
if(done[i]&&finds(node[i])!=finds(node[Elem]))
{
flag=0;
}
}
printf("Case #%d\n",++kase);
if(!flag)
{
cout<<"some beads may be lost"<<endl;
}
else
{
for(int i=1; i<=50; i++)
{
dfs(i);
}
}
if(T)
printf("\n");
}
}