【发布时间】:2017-01-19 00:33:08
【问题描述】:
我在 SO 阅读了关于在有向图中找到循环的讨论 here。现在,OP 声称我们需要验证 两 件事:
- 从
u到v有一个后沿 -
v在递归堆栈中
为什么我们需要第二次测试?你能举个例子来证明它的必要性吗?
【问题讨论】:
标签: algorithm graph computer-science
我在 SO 阅读了关于在有向图中找到循环的讨论 here。现在,OP 声称我们需要验证 两 件事:
u 到v 有一个后沿
v 在递归堆栈中为什么我们需要第二次测试?你能举个例子来证明它的必要性吗?
【问题讨论】:
标签: algorithm graph computer-science
好吧,您可能对有向图中的后边的定义和无向图中的后边的定义感到困惑。是的,它们是不同的。
在无向图中,后边是从当前顶点到已经访问过的顶点的边。 (正如您提到的链接中的 OP)。
在有向图中,后边的定义是不同的。有向图中的后边是从当前顶点到灰色顶点的边(该顶点的 DFS 已经开始但尚未完成),这意味着它仍在递归堆栈中。
因此,如果您在有向图中采用后边的定义,那么是的,它足以检测循环。
但是,如果您将后边定义为无向图中的定义,那么您还需要确保 v 在递归堆栈中以检测循环。
示例:
考虑 DFS 访问顺序为A -> B -> C。
在这个例子中,边 <A,C> 是下图中的后边(因为 C 已经被访问过)。
但它不是这个有向图中的后边——C 已经被访问过但不在递归堆栈中,这意味着它不是一个循环。
【讨论】:
当它是交叉边缘而不是后边缘时,需要进行第二次测试。交叉边是指从一个顶点到已经访问过的顶点的边,无论位置如何。 后边指的是指向起始顶点的祖先的边,该祖先仍在递归堆栈中。就如何提出问题而言,OP 将后边缘称为指向另一个已访问边缘的边缘,但更准确的解释是交叉边缘。知道它是一个后边缘就足够了,因为它意味着第二步。当第一个是交叉边缘时需要这些步骤,因为第二个证明交叉边缘是后边缘。在有向图中,交叉边并不总是意味着发生循环。这是一个例子:
vertices a,b,c,d
a->b
a->c
b->d
d->c
根据处理的顺序,d->c 可以被认为是交叉边缘,因此需要第 2 步来检测循环。不幸的是,后边缘和交叉边缘经常混淆,导致这样的混乱。这是一个链接到另一个描述两者之间差异的链接,Depth-First Search。
【讨论】: