交互式图论学习
交互式图论学习
Guest User
Using app without sign in
欧拉路径与回路查找器
在无向图中找到恰好访问每条边一次的路径
选择算法并生成步骤以开始可视化
欧拉路径恰好经过图的每条边一次;欧拉回路则经过每条边一次并返回起点。莱昂哈德·欧拉于 1736 年证明柯尼斯堡七桥问题不存在这样的走法,从而奠定了图论。
存在性易于判定:连通无向图恰在每个顶点度为偶数时有欧拉回路,恰在正好零个或两个顶点度为奇数时有欧拉路径。Hierholzer 算法在 O(E) 内构造该走法:沿未使用的边前进直到回到起点,然后从仍有未使用边的顶点反复拼接绕行环。
欧拉路径解决扫雪、街道清扫和邮件投递等路线巡查问题,在生物信息学中由 k-mer 重建 DNA 序列,并生成德布鲁因序列。基于奇偶性的存在性测试是经典面试题,将其与难得多的哈密顿问题区分开。
存在性判定纯粹是计数,一趟即可完成。只有在判定通过之后,才用 Hierholzer 而不是朴素回溯去构造这条路径。
// 存在性判定(连通的无向图):
// 0 个奇度结点 -> 存在欧拉回路
// 2 个奇度结点 -> 存在两者之间的欧拉路径
// 其他情况 -> 两者都不存在
Hierholzer(图, 起点):
栈 = [起点]; 路径 = []
当栈非空时:
u = 栈.顶
若 u 还有未使用的关联边 (u,v):
把该边标记为已使用
栈.压入(v)
否则:
路径.追加(栈.弹出())
反转 路径Hierholzer 之所以奏效,是因为它从不需要猜测。它一直走到走不动为止;在所有结点度数都为偶数的图上,这只可能发生在起点。随后它从仍有未使用边的结点处把绕行环拼接进来。每个结点被进入和离开的次数相同,而这正是偶数度所保证的,因此这些片段总能合并成一条闭合的路径。
在两个共用一个结点的三角形上构造欧拉回路,邻居按字母顺序选取。
示例图: 无向边 A-B、B-C、C-A 构成一个三角形,C-D、D-E、E-C 构成第二个,两者在 C 处相连。
欧拉回路是 A 到 B 到 C 到 D 到 E 到 C 到 A,恰好用完全部六条边并回到起点。注意 C 在路径中出现了两次,这是允许且预期之中的:欧拉路径可以自由地重复经过结点,唯一不允许的是重复使用某条边。这正是它与哈密顿路径的全部差别,后者要求每个结点只访问一次,而根本不关心边。
时间: O(V + E) · 空间: O(V + E)
度数统计是对所有边扫一遍,为 O(E);连通性检查是一次遍历,为 O(V + E)。Hierholzer 对每个结点出现只压栈一次、弹栈一次,并把每条边恰好标记为已使用一次,因此是 O(E),前提是每个结点都保留一个指向其邻接表的指针,而不是每次都从头重扫。若没有这个指针,内层查找会退化为 O(V·E)。空间开销是已使用边的标记,再加上栈与路径,二者各持有 O(E) 个条目。与哈密顿路径的对比很值得一提:欧拉问题是线性的,哈密顿问题是 NP 完全的,原因纯粹在于边可以通过度数在局部计数,而结点不行。
欧拉类问题很容易;表面上相似的哈密顿类问题却不是。先确认你面对的究竟是哪一个。
| 替代算法 | 以下情况更合适 | 代价 |
|---|---|---|
| 哈密顿路径 | 你要求的是每个「结点」访问一次,而不是每条边。它是 NP 完全的,因此适用的方法完全不同。 | 指数级 |
| 中国邮递员问题 | 存在奇度结点,但你仍想要一条覆盖所有边的闭合路线,允许以最小代价重复经过某些边。 | O(V^3) |
| Fleury 算法 | 你想不用栈来构造路径。概念上更简单但更慢,因为它要靠检测桥来回避它们。 | O(E^2) |
| De Bruijn 图 | 基因组组装之类的场景,其中 De Bruijn 图上的欧拉路径可重建出一条序列。 | O(V + E) |