欧拉回路
1.题目描述:
欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?
输入描述:
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是节点数N ( 1 < N < 1000 )和边数M;随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号(节点从1到N编号)。当N为0时输入结束。
输出描述:
每个测试用例的输出占一行,若欧拉回路存在则输出1,否则输出0。
示例1
输入
复制
3 3
1 2
1 3
2 3
3 2
1 2
2 3
0
输出
复制
1
0
2.基本思路
欧拉回路定义:于无向图而言,存在欧拉回路的图指的是能通过图中所有的边有且仅有一次,然后可以回到原点的图。
需要满足两个要求:
①图是连通图(除了孤立顶点以外)→采用并查集进行判断
②图中所有顶点的度数(入度+出度)均为偶数→采用inDegree数组进行标记
注意点:孤立点指的是只存在单点回路或不存在任何与其相连的边的顶点。
以下图为例Figure.1中的结点2、4均为孤立顶点,Figure.2为非连通图。
需要注意一下用例:
用例:
7 8
2 6
5 4
6 6
2 1
2 2
5 6
1 4
5 5
对应输出应该为:
1
该例中很明显结点3,7是孤立的结点,但欧拉图只要求通过所有的边,然后能回到原点即可,因此对于孤立的点可以无需考虑,这里采用set存储非孤立的结点的编号。后续统计度数的奇偶性以及连通分量的个数时可以忽略这些孤立的顶点不管。
3.代码实现
#include <iostream>
#include <set>
#define N 1001
using namespace std;
int Tree[N];
int inDegree[N];
set<int> Mapping;
int findRoot(int x){
if(Tree[x]==-1)return x;
else{
Tree[x]=findRoot(Tree[x]);
return Tree[x];
}
}
int main()
{
int n,m;
int a,b;
while(~scanf("%d",&n)){
if(n==0)break;
scanf("%d",&m);
for(int i=1;i<=n;i++){
Tree[i]=-1;
inDegree[i]=0;
}
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
if(a==b)continue;//单点回路忽略不计
Mapping.insert(a);
Mapping.insert(b);
inDegree[a]++;
inDegree[b]++;
a = findRoot(a);
b = findRoot(b);
if(a!=b)Tree[a]=b;
}
int cnt=0;//统计连通分量的个数
for(auto it=Mapping.begin();it!=Mapping.end();it++){
if(Tree[*it]==-1)cnt++;
}
if(cnt!=1){
printf("0\n");
}
else{
int cnt1=0;//统计度数为奇数的结点个数
for(auto it=Mapping.begin();it!=Mapping.end();it++){
if(inDegree[*it]&1==1){
cnt1++;
}
}
if(cnt1==0){
printf("1\n");
}
else{
printf("0\n");
}
}
}
return 0;
}
/*
3 3
1 2
1 3
2 3
3 2
1 2
2 3
0
*/