题目描述
欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?
输入格式
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是节点数N ( 1 < N < 1000 )和边数M;随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号(节点从1到N编号)。当N为0时输入结
束。输出格式
每个测试用例的输出占一行,若欧拉回路存在则输出1,否则输出0。
输入样例
3 3
1 2
1 3
2 3
3 2
1 2
2 3
0输出样例
1
0
欧拉通路/回路的判定
有向图
- 欧拉通路:图是连通的,图中只有两个奇度点,分别是欧拉通路的两个端点。对于欧拉通路,除起点、终点外,每个点如果进入,显然一定要出去,因此都是偶点。
- 欧拉回路:图是连通的,点均为偶度点。对于欧拉回路,每个点进入、出去的次数相等,因此没有奇点。
无向图
- 欧拉通路:图是连通的,除两顶点外其余点的入度等于出度,且这两个顶点中,一个顶点入度比出度大1(起点),另一个入度比出度小1(终点)
- 欧拉回路:图是连通的,图中所有点的入度等于出度。
思路
对于判定欧拉通路/回路是否存在的问题,显然我们只需判断两点:
- 图是否联通。
- 顶点度数的统计与判断。
对于第一点,我们可以用并查集来统计连通分量/强连通分量的个数。如果个数为1,则转至第二点。否则,不存在欧拉通路/回路。
对于第二点,我们只需统计结束后做一个简单判断。
源程序
#include <bits/stdc++.h>
#define MAXN 1005
using namespace std;
int n,m,degree[MAXN],father[MAXN];
int read() //快读
{
int sum=0;
char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9'){
sum=sum*10+c-'0';
c=getchar();
}
return sum;
}
int find(int x) //并查集
{
if(x==father[x])return x;
return father[x]=find(father[x]); //路径压缩
}
void Union(int x,int y) //合并
{
x=find(x);
y=find(y);
if(x!=y)father[x]=y;
return ;
}
int main()
{
while(1){
n=read();
if(n==0)break;
m=read();
for(int i=1;i<=n;i++){ //初始化
degree[i]=0;
father[i]=i;
}
for(int i=1;i<=m;i++){ //统计顶点度数并建立并查集
int x=read(),y=read();
degree[x]++;
degree[y]++;
Union(x,y);
}
int cnt=0; //记录连通分量个数
for(int i=1;i<=n;i++)
if(i==father[i])
cnt++;
if(cnt!=1)cout<<0<<endl;
else{
int num=0; //记录奇度点个数
for(int i=1;i<=n;i++)
if(degree[i]&1)num++;
if(num==0)cout<<1<<endl; //不存在奇度点
else cout<<0<<endl;
}
}
return 0;
}