欧拉图(Eulerian Graph)
欧拉通路 (Eulerian Path/Trail):又称欧拉路径,通过图中每一条边恰好一次的通路(顶点可以重复访问)。
欧拉回路 (Eulerian Circuit/Cycle):首尾顶点相接的欧拉通路(即一个起点和终点相同的欧拉通路)。
具有欧拉回路的无向图称为欧拉图。
具有欧拉通路但不具有欧拉回路的无向图称为半欧拉图。
非形式化地讲,欧拉图就是从任意一个点开始都可以一笔画完整个图,半欧拉图必须从某个点开始才能一笔画完整个图。
要判断一个无向图是否为欧拉图或半欧拉图,有以下两个必要条件:
- 欧拉图:图中所有顶点的度数均为偶数。
- 半欧拉图:图中恰有两个顶点的度数为奇数。
如果一个无向图满足上述第一个条件,则它是欧拉图。如果满足第二个条件,则它是半欧拉图。
对于有向图(有向欧拉图):
- 有向欧拉图:每个顶点的入度等于出度,并且整个图必须是强连通图。这意味着,从图的任意一个顶点,可以沿着有向边到达任何其他顶点。
- 有向半欧拉图:图中只有两个顶点的入度与出度不相等,其中一个顶点的出度比入度大1,另一个顶点的入度比出度大1。其余所有顶点的入度必须等于出度。图必须是弱连通的,即在将所有边看作无向边后,图必须连通。
代码:判断是否为欧拉图或半欧拉图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | /**************************************************************** * 代码作者: Alex Li * 创建时间: 2026-06-06 11:57 * 最后修改: 2026-06-06 12:18 * 文件描述: 在输入保证为连通无向图时,判断其是否为欧拉图或半欧拉图;时间复杂度 O(n + m) * 核心算法: 在连通图前提下,只需统计奇度点个数即可判断欧拉回路或欧拉通路 ****************************************************************/ #include <iostream> #include <vector> using namespace std; int n, m; vector<vector<int>> graph; vector<int> degree; bool isEulerianGraph() { // 无向图存在欧拉回路,当且仅当所有顶点度数均为偶数。 for (int i = 1; i <= n; ++i) { if (degree[i] % 2 != 0) { return false; } } return true; } bool hasTrail() { int oddCount = 0; for (int i = 1; i <= n; ++i) { if (degree[i] % 2 != 0) { ++oddCount; } } // 无向图存在欧拉通路,当且仅当奇度点个数为 0 或 2。 return oddCount == 0 || oddCount == 2; } int main() { cin >> n >> m; graph.assign(n + 1, vector<int>()); degree.assign(n + 1, 0); // 输入前提:该无向图是连通图。 // 输入格式: // n m // 接下来 m 行,每行一条无向边 u v for (int i = 0; i < m; ++i) { int u, v; cin >> u >> v; // 无向边要双向加入邻接表,同时分别统计两个端点的度数。 graph[u].push_back(v); graph[v].push_back(u); ++degree[u]; ++degree[v]; } if (isEulerianGraph()) { cout << "Eulerian graph\n"; } else if (hasTrail()) { cout << "Semi-Eulerian graph\n"; } else { cout << "Not Eulerian\n"; } return 0; } |
