如何检查合并 2 个节点后的两个 DAG 是否没有循环?

问题描述

给定 2 个随机 DAG,它们可能有也可能没有公共节点。我们从每个节点中随机选取一个节点,分别称它们为 A 和 B。 A != B

合并前如何检查,如果我们将节点B合并到节点A(通过将B的边复制到A中的边,并销毁节点B),是否没有循环?

我想避免穷举搜索 - 当我们“虚拟地”合并这些节点,然后在结果图中搜索所有节点时,搜索从该节点到自身的路径。

一个节点有唯一的ID,大致定义如下:

class Node:
  def __init__(self,id):
    self.id = id
    # set of outgoing nodes
    self.deps = set()
    # set of incoming nodes
    self.dependants = set()

# in the end,I want to write function like this:
def check(A,B):
  assert isinstance(A,Node) and isinstance(B,Node)
  if "there will be no cycles":
    return True # we can merge
  else:
    return False # we can not merge

我不需要代码、算法描述或算法名称就足够了。

解决方法

  • B 不是 A 的前驱时,没有循环。
  • 如果 BA 的直接前驱,并且没有 B 边的 A 不是 A 的前驱。没有循环
  • 否则就有循环

嗯,伪代码

if not A in DFS(B) // B is not a predecessor
  return noCycle
if A in B.outEdges and not A in DFS(B less A-Edge) // direct predecessor
  return noCycle
return cycle 

可以优化为

if not A in DFS(B less A-Edge) 
  return noCycle
return cycle 

考虑

B->C->A

合并 A 和 B 将导致

C->A->C

这是一个循环。

B->A
 ->C

成为

A->C

哪里

B->A
 ->C->A

变成一个循环

A->C->A