哥尼斯堡是位于普累格河上的一座城市,它包含两个岛屿及连接它们的七座桥,如下图所示。
可否走过这样的七座桥,而且每桥只走过一次?瑞士数学家欧拉(Leonhard Euler,1707—1783)最终解决了这个问题,并由此创立了拓扑学。
这个问题如今可以描述为判断欧拉回路是否存在的问题。欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个无向图,问是否存在欧拉回路?
输入格式:
输入第一行给出两个正整数,分别是节点数N (1≤N≤1000)和边数M;随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号(节点从1到N编号)。
输出格式:
若欧拉回路存在则输出1,否则输出0。
输入样例1:
6 10
1 2
2 3
3 1
4 5
5 6
6 4
1 4
1 6
3 4
3 6
输出样例1:
1
输入样例2:
5 8
1 2
1 3
2 3
2 4
2 5
5 3
5 4
3 4
输出样例2:
0
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
// 包含标准输入输出库的头文件
#include<stdio.h>
// 定义一个函数Find,参数为一个数组f和一个整数x。这个函数的思路类似于并查集。
int Find(int f[],int x){
// 如果f[x]等于x,说明x是它的根节点,直接返回x。
if(f[x]==x) return x;
// 如果f[x]不等于x,说明f[x]指向的节点不是x的根节点,那么我们找到f[x]所指向的节点的根节点,然后进行路径压缩,直接将f[x]指向根节点。
return f[x]=Find(f,f[x]);
}
// 主函数开始
int main()
{
// 定义两个大小为1001的数组in和f,其中in用于存储每个集合的元素数量,f用于存储并查集的根节点。
int in[1001],f[1001],N,M;
// 将f数组初始化为每个元素是其本身的值,表示每个集合的根节点就是其自身。
for(int i=1;i<=1000;i++)
f[i]=i;
// 从标准输入读取两个整数N和M,分别表示节点数和边数。
scanf("%d%d",&N,&M);
// 对于M次操作,每次读取两条边a和b。
for(int i=0;i<M;i++)
{
int a,b;
// 从标准输入读取a和b的值。
scanf("%d%d",&a,&b);
// 分别找到a和b所在的集合的根节点n和m。
int n=Find(f,a),m=Find(f,b);
// 如果a和b不在同一个集合中,那么将它们合并到同一个集合中。这通过让n等于m来实现。
if(n!=m)f[n]=m;
// 对a和b所在的集合的元素数量加一。注意这里的in数组并不存储元素本身,而是用于存储每个集合的元素数量。
in[a]++;in[b]++;
}
// 初始化计数器cnt为0。用于统计所有元素所在的集合的元素数量为偶数的个数。
int cnt=0;
// 对每个元素所在的集合进行遍历。
for(int i=1;i<=N;i++)
// 如果元素所在的集合的元素数量是偶数,那么将计数器加一。
if(in[i]%2==0)cnt++;
// 初始化计数器cont为0。用于统计所有元素所在的集合的根节点是其自身的个数。
int cont=0;
// 对每个元素所在的集合进行遍历。
for(int i=1;i<=N;i++)
// 如果元素所在的集合的根节点就是其自身,那么将计数器加一。
if(f[i]==i)cont++;
// 如果所有元素所在的集合的元素数量都是偶数并且只有一个集合没有与其他集合合并,那么输出"1",否则输出"0"。这里的"1"代表存在欧拉回路,"0"代表不存在欧拉回路。
if(cnt==N&&cont==1)printf("1\n"); // 输出1表示存在欧拉回路。 否则 printf("0\n"); 输出0表示不存在欧拉回路. 欧拉回路存在的话,从任意一点出发都可以回到原点,所以遍历次数必须是偶数次. 同时只有一个点没有被遍历到. 只有一点没有被遍历到, 就说明只有一条回路没有被遍历到. 所以遍历次数必须是奇数次. 因此只有当遍历次数是偶数次且只有一个点没有被遍历到的时候, 才能形成欧拉回路. 输出1表示存在欧拉回路, 输出0表示不存在欧拉回路.
}