我需要找到有向图中两个节点[src,dest]之间任何路径上的所有边。
意味着每条边(从基部到头部)必须满足:
我可以收集连接到src的所有边,并收集与dest相反方向连接的所有边,并计算它们的交集。
但必须有一个算法,对吧? (不知道是否可以提高效率)所以我正在寻找名称,或用现有算法解决它的聪明解决方案。
答案 0 :(得分:2)
如果您只回答一次问题,那么评论您问题的人员是正确的:您提出的解决方案是正确而快速的。但是,如果您在固定图表中针对不同的src和dest多次回答您的问题,则可以使用" index"加快查询的信息。
Tarjan's algorithm会在O(V + E)时间内将有向图分解为强连通分量(SCC)。强连通分量是一组顶点,通过跟随有向图可以相互连接。
强连通组件集本身将形成有向无环图(DAG)。
如果src和dest在同一个SCC中,那么你要查找的边集恰好是SCC中的边集。
如果从DAG中包含src的SCC无法访问包含dest的SCC,则没有从src到dest的路径,因此您要查找的边集是空的。
如果可以从包含src的SCC访问包含dest的SCC,则需要在DAG中找到从src SCC到dest SCC的所有路径,这是一个非常简单的动态编程问题。然后你想要的边缘集是src SCC和dest SCC之间所有SCC的边集,以及" pullbacks" DAG中相关路径的边缘到原始图中的边缘。
这可能听起来令人困惑,但维基百科页面上的图表可能有助于澄清。
答案 1 :(得分:0)
要获得整体结果,我会报告我的所作所为。
我在提到的问题算法中实现了。 (让我们称之为 thigg的算法,因为没人提到名字)
Thigg的算法:
for each node in the graph:
if there is a path from src to this node
and a path from this node to dest,
push node to the result list.
正如Edward Doolittle在他的answer中提到的那样,通过识别Strongly-Connected-Components并将它们减少到一个节点,可以优化图形。这将减少每次运行算法的工作量。
我使用Boost-Graph-Library(没有SCC优化)实现了thiggs算法,其中a
是源,b
是目标顶点:
我使用广度优先搜索来获取a
可到达的所有顶点的列表:
boost::breadth_first_search(graph, a, visitor(vis));
vis是一个自定义访问者,它将所有访问过的顶点放入列表中。 然后它恢复图形以获得所有可以达到b
的顶点boost::breadth_first_search(boost::make_reverse_graph(graph), b, visitor(vis));
最后计算交集:
std::set_intersection(froma.begin(),froma.end(),fromb.begin(),fromb.end(),back_inserter(inters));
Note您的图表必须是双向的才能使用make_reverse_graph
。
该算法也适用于问题中提到的边缘。