我发现了等待图(wait-for graphs),我想知道,是否有有效的算法可以检测在有向图中添加一条边是否会导致出现环路?
所讨论的图是可变的(可以添加或删除节点和边)。我们只需要知道是否存在环路即可(以防止添加一个冒犯边)。
当然,可以使用计算强连通分量(例如Tarjan算法)的算法来检查新图是否为无环图,但每次添加边时都要重新运行它似乎相当低效。
我发现了等待图(wait-for graphs),我想知道,是否有有效的算法可以检测在有向图中添加一条边是否会导致出现环路?
所讨论的图是可变的(可以添加或删除节点和边)。我们只需要知道是否存在环路即可(以防止添加一个冒犯边)。
当然,可以使用计算强连通分量(例如Tarjan算法)的算法来检查新图是否为无环图,但每次添加边时都要重新运行它似乎相当低效。
然而,如果你想提高理论运行时间,以下是一些提示(主要表明这并不容易)。假设我们的目标是以O(1)的时间测试是否存在从v到u的有向路径。在这种情况下,关键词是DAG的传递闭包(即,如果DAG中存在从u到v的有向路径,则其中包含边缘(u,v))。不幸的是,在动态设置中维护传递闭包似乎并不简单。有几篇论文考虑了这个问题,我找到的所有论文都是STOC或FOCS论文,这表明它们非常复杂。我找到的最新(也是最快)的结果是Sankowski的论文“Dynamic Transitive Closure via Dynamic Matrix Inverse”(http://dl.acm.org/citation.cfm?id=1033207)。
即使你愿意理解其中一种动态传递闭包算法(甚至想要实现它),它们也不会给你任何加速,因为这些算法是针对具有大量连接查询(然后可以在O(1)时间内执行)和图中仅有少量更改的情况设计的。然而,目标仍然是使这些更改比重新计算传递闭包更便宜。但是,这种更新仍然比单个连接性检查慢。因此,如果您需要在每次连接查询上进行更新,则最好使用上述简单方法。
那么,为什么我要提到维护传递闭包的方法,如果它不符合您的需求呢?这表明,仅消耗O(1)查询时间的算法搜索可能不会比使用BFS / DFS的简单算法更快地解决问题。您可以尝试获取查询时间,该时间比O(m)更快但比O(1)更差,同时更新速度也比O(m)更快。这是一个非常有趣的问题,但对我来说似乎是一个非常雄心勃勃的目标(所以可能不要花太多时间去尝试实现它...)。
这是我最近在稍微不同的情况下遇到的问题(互相依赖编译器指令的最佳排序)。
虽然我无法改进O(n*n)的理论界限,但经过一定量的实验和对我的情况做出的启发式假设(例如,假设初始排序没有恶意地创建),以下是性能方面最好的折衷算法。
(在我的情况下,我有一个可以接受的“右侧失败”:在添加初始节点和弧之后(这是有保证的),优化器偶尔拒绝添加更多弧,其中实际上可以添加一个。当完全执行此算法时,此近似不是必需的,但如果您希望这样做,则可以使用此算法,并因此进一步限制其运行时间。)
当图形按拓扑排序时,保证它是无环的。在第一阶段中,当我有一个静态的节点和弧块要添加时,我添加了节点,然后按拓扑排序进行排序。
在第二阶段中,添加其他弧时,在考虑从A到B的弧时有两种情况。如果A已经位于B的左侧进行了排序,则可以简单地添加一条弧,并且不会生成循环,因为列表仍然按拓扑排序。
如果B在A的左侧,则考虑从B到A之间的子序列,并将其分成两个不相交的序列X,Y,其中X是可以到达A的节点(Y为其他节点)。如果A从B中不可达,即没有直接弧从B进入X或到达A,则可以在添加A到B弧之前重新排序XABY,显示它仍然是无环的并保持拓扑排序。这里与朴素算法相比的效率是我们只需要考虑B和A之间的子序列,因为我们的列表已按拓扑排序:A不能从A右侧的任何节点到达。对于我的情况,局部重排序最频繁且最重要,这是一个重要的收益。
由于我们不在序列X、A、B、Y内重新排序,因此任何在同一序列内开始或结束的弧仍然正确排序,而且在每个侧面上都相同,在飞越左侧到右侧侧面的任何弧也是如此。任何在侧面和X、A、B、Y之间的弧也仍然正确排序,因为我们的重新排序仅限于此本地区域。因此,我们只需要考虑四个序列之间的弧。依次考虑我们最终排序XABY的每个可能的“有问题”的弧:YB YA YX BA BX AX。我们的初始顺序是B[XY]A,因此不能出现AX和YB。X可以到达A,但Y不能,因此YX和YA不会发生,否则可以从Y弧的源头(可能通过X)到达A,这是矛盾的。我们接受性的标准是没有链接BX或BA。因此,没有问题的弧,而且我们仍然按拓扑排序。
我们唯一可接受的标准(即A无法从B到达)足以在添加弧A->B时创建一个循环: B -(X)-> A-> B,因此反之亦然。https://dev59.com/D3VC5IYBdhLWcg3wixs0#261621
如果我们有一个已排序的节点列表:
1, 2, 3, ..., x, ..., z, ...
Such that each node is waiting for nodes to its left.