DAG - 确保存在单个源和单个接收器的算法

时间:2013-12-12 01:02:08

标签: algorithm graph-theory directed-acyclic-graphs

我必须确保我们的应用程序中的图形是具有唯一来源和独特接收器的DAG。

具体而言,我必须确保对于给定的起始节点和结束节点(两者都在一开始就知道),图中的每个节点都位于从起始节点到结束节点的路径上。

我已经有了Tarjan算法的实现,我用它来识别周期,以及一个拓扑排序算法,我可以运行一旦Tarjan的算法报告图形是DAG。

确保图表符合此标准的最有效方法是什么?

4 个答案:

答案 0 :(得分:1)

如果您的图表由邻接矩阵表示,那么如果矩阵的第x列为0,则节点x是源节点,如果矩阵的行x为0,则节点x是汇聚节点。您可以运行两次快速传递用于计算0的行数和列数的矩阵,以确定存在多少源和接收器以及它们是什么。这需要时间O(n 2 )并且可能是检查此问题的最快方法。

如果您的图表由邻接列表表示,您可以通过检查任何节点是否没有传出边缘来查找时间O(n)中的所有汇聚节点。您可以通过为每个节点维护一个布尔值来查找所有接收器,该布尔值指示它是否有任何传入边缘,最初为false。然后,您可以在时间O(n + m)中迭代列表中的所有边缘,标记具有传入边缘的所有节点。然后,未标记为具有传入边缘的节点是源。这个过程花费时间O(m + n)并且开销很小,可能是最快的方法之一。

希望这有帮助!

答案 1 :(得分:0)

简单的广度或深度优先搜索应满足此要求。首先,您可以保留一组包含您已经看到的汇聚​​节点的节点。其次,您可以保留使用BFS / DFS发现的一组节点。然后,如果存在单个连接组件,则将连接图形。假设您正在为图表使用某种邻接列表样式表示,算法将如下所示:

create an empty queue
create an empty set to store seen vertices
create an empty set for sink nodes

add source node to queue

while queue is not empty
    get next vertex from queue, add vertex to seen vertices
    if num of adjacent nodes == 0
        add sink nodes to sink node set
    else
        for each node in adjacent nodes
        if node is not in seen vertices
            add node to queue

return size of sink nodes == 1 && size of seen vertices == total number in graph

这将是图中顶点和边数的线性。

请注意,只要您知道要从哪个源顶点开始,这也将确保单个源的属性:BFS / DFS将不会发现作为源的任何其他顶点,因此大小看到的顶点不会是图中的总数。

答案 2 :(得分:0)

如果您的算法将弱连接的DAG作为输入,则假设只有一个节点s的入度为零,并且只有一个节点t的出度为零,而所有其他节点都为正-degree和out-degree,然后s可以到达所有其他节点,所有其他节点都可以到达t。通过矛盾,假设存在s无法到达的节点v。由于没有节点可以达到s,也就是说,v也无法达到s。因此,v和s断开连接,这与假设相矛盾。另一方面,如果DAG没有弱连接,它肯定不能满足您的要求。总而言之,您可以先使用BFS / DFS计算DAG的弱连通分量,同时记住入度或出度为零的节点数。该算法的复杂性为O(| E |)。

答案 3 :(得分:0)

首先,从源节点开始在图表上执行DFS,正如您所说的那样,事先已知。如果你遇到后沿[1],那么你有一个循环,你可以退出并出错。在此遍历期间,您可以确定是否存在无法从源[2]访问的节点并采取相应的操作。

一旦确定图形是DAG,就可以确保每个节点位于从源到接收器的路径上,由源从源开始,如下所示:

bool have_path(source, sink) {
    if source == sink {
        source.flag = true
        return true
    }

    // traverse all successor nodes of `source`
    for dst in succ(source) {
        if not dst.flag and not have_path(dst, sink)
           return false // exit as soon as we find a node with no path to `sink`
    }
    source.flag = true;
    return true
}

过程have_path在每个节点中设置一个布尔flag,从该节点到接收器存在一些路径。同时,该过程仅遍历从源可到达的节点,并且它遍历从源可到达的所有节点。如果过程返回true,则从源可到达的所有节点都位于接收器的路径上。第一阶段已经处理了无法访问的节点。


[1]边缘,将具有较大DFS编号的节点链接到DFS编号较小的节点,该节点尚未完全处理,即仍在DFS堆栈上

[2]例如他们没有指定的DFS编号