在有向图中进行有效搜索

时间:2011-01-04 04:28:37

标签: c++ traversal directed-graph

我有一个包含数百万个顶点和边的有向图。给出了一组顶点,我们假设它们被称为“START_POINTS”。还给出了另一组顶点,称为“END_POINTS”。问题是找到哪个END_POINTS可以从哪个START_POINTS到达。

以下是一个例子:

START_POINTS: S1 S2 S3 S4 S5 S6 S7 ... 
END_POINTS  : E1 E2 E3 E4 E5 E6 E7 ... 

该算法应该能够说明以下内容:

S1 can reach to E1, E2, E6
S2 can reach to E9, E10
S3 cannot reach any END_POINT
S4 can reach to .....
....

可能无法从任何START_POINT到达某些END_POINTS。

现在,问题是:实施它的最有效方法是什么?

我尝试从每个START_POINT逐个开始,并使用深度优先搜索找到可达的END_POINTS(或者BFS,它确实更改了运行时间)。但是,它需要花费很多时间,因为有很多START_POINTS(还有很多END_POINTS)。

可以优化搜索,因为START_POINTS的跟踪路径之间存在巨大的重叠。需要记住哪些路径可以到达哪个END_POINTS。实现这一目标的最有效方法是什么?这可能是众所周知的问题,但我还没有找到解决方案。

1月6日编辑:

我尝试实现highBandWidth的想法(以类似于Keith Randall提出的方式):对于每个节点,如果此节点不是START或END点,则将所有输入连接到输出,然后删除节点。

foreach NODE in NODES
    Skip if NODE is START_POINT or END_POINT
    foreach OUTPUT_NODE of NODE
        Disconnect NODE from INPUT_NODE
    end
    foreach INPUT_NODE of NODE
        Disconnect NODE from INPUT_NODE
        foreach OUTPUT_NODE of NODE
            Connect INPUT_NODE to OUTPUT_NODE
        end
    end
    Remove NODE from NODES
end

这开始非常快并且很快变得非常慢,主要是因为剩余节点的输入/输出计数变得非常大并且循环嵌套会导致性能下降。知道如何提高效率吗?

3 个答案:

答案 0 :(得分:1)

这可能有点矫枉过正,但您可能需要查看Dijkstra。我在创建自己的虚拟节点路由表时曾经使用过它。在这种情况下,所有节点的值都为1,这意味着每个节点的成本相同。

答案 1 :(得分:1)

只需修剪图形即可删除未出现在“开始节点”或“结束节点”中的所有节点,将其从入站节点的边缘替换为出站目标。完成后,遍历所有其他节点(即Start或End节点),并将其入站节点的边缘添加到其出站节点,而不删除这些节点。在几个类似Djikstra的迭代中,你应该留下从开始到结束的边缘。

答案 2 :(得分:0)

首先,运行strongly connected components算法。然后将所有连接的组件合同到一个节点。然后执行图表的topological sort。然后,在一次通过中,您可以计算哪些起始节点可以到达图中的每个节点(将每个起始节点初始化为集合{s},然后按拓扑顺序执行每个节点的入局边缘的并集)。

你有一个潜在的问题,答案可能和#start nodes * #endode node一样大,这可能很大。希望你有一些大型SCC可以收缩到单个节点,因为这可以使答案更加简洁(同一个SCC中的所有起始节点都可以到达相同的位置,所以你只需要在你的集合中使用一个代表)。 p>