虚虚实实 题解
题目描述
给定一个无向图,判断是否存在一条路径能够:
- 经过所有边恰好一次
- 经过所有点
- 不要求回到起点
即判断图中是否存在欧拉路径(Eulerian Path)。
核心结论
答案: 当且仅当图连通且奇度数顶点个数为 0 或 2 时,存在欧拉路径。
- 奇度数顶点个数为 0:存在欧拉回路
- 奇度数顶点个数为 2:存在欧拉路径(从奇度数顶点开始和结束)
标程实现
#include <bits/stdc++.h>
using namespace std;
int de[33], fa[33];
int f(int x) {
return fa[x] == x ? x : fa[x] = f(fa[x]);
}
int main() {
int _;
cin >> _;
while (_--) {
int n, m, i, x, y;
cin >> n >> m;
// 初始化
for (i = 1; i <= n; i++) {
fa[i] = i;
de[i] = 0;
}
// 读入边并维护度数和连通性
for (i = 0; i < m; i++) {
cin >> x >> y;
de[x]++;
de[y]++;
fa[f(x)] = f(y); // 并查集合并
}
// 检查连通性和奇度数顶点个数
int cnt = 0, jud = 1;
for (i = 1; i <= n; i++) {
if (f(i) != f(1)) jud = 0; // 检查连通性
cnt += de[i] & 1; // 统计奇度数顶点
}
if (!jud || cnt > 2) cout << "Xun\n";
else cout << "Zhen\n";
}
}
算法解释
欧拉路径判定条件
对于无向图,存在欧拉路径的充要条件是:
- 图连通
- 奇度数顶点个数为 0 或 2
算法步骤
-
初始化:
- 使用并查集维护连通性
- 度数数组记录每个顶点的度数
-
读入边:
- 更新两个端点的度数
- 使用并查集合并两个顶点
-
检查条件:
- 连通性:检查所有顶点是否与顶点1在同一连通分量
- 度数条件:统计奇度数顶点个数
关键技巧
de[i] & 1
:快速判断度数是否为奇数- 并查集路径压缩:
fa[x] = f(fa[x])
- 只需检查与顶点1的连通性,因为连通分量内部任意两点连通
并查集学习资源
如果对并查集算法不熟悉,推荐观看这个1分钟快速入门视频: 《1分钟学会并查集》
示例分析
示例1:
- 图连通,奇度数顶点个数为2(顶点1和顶点3)
- 存在欧拉路径:1→2→3→1→4→3
示例2:
- 图不连通
- 不存在欧拉路径
复杂度分析
- 时间复杂度:
,其中
是阿克曼函数的反函数
- 空间复杂度: