我有一个无向图,最初没有边。现在,在每个步骤中添加或删除边缘,并且必须检查图形是否至少有一个圆。可能最简单的条件是
连通分量+边数< =节点数。
由于我上面提到的“步骤”被执行了数百万次,所以这个检查必须非常快。所以我想知道根据每个步骤中只有一个边缘发生变化的事实来检查条件的快速方法。
有什么建议吗?
答案 0 :(得分:3)
如果您热衷于此,可以尝试实现完全动态的图形连接数据结构,如"Poly-logarithmic deterministic fully-dynamic graph algorithms I: connectivity and minimum spanning tree" by Jacob Holm, Kristian de Lichtenberg, Mikkel Thorup中所述。
添加边缘时,检查两个端点是否已连接。如果不是,则连接组件的数量减少一个。删除边缘后,检查两个端点是否已连接。如果不是,则连接组件的数量增加1。边插入和删除的摊销运行时间为O(log^2 n)
,但我可以想象常数因子非常高。
newer result有更好的界限。还有experimental evaluation的一些动态连接算法也考虑了实现细节。还有一个Javascript implementation。我不知道它有多好。
我想在练习中你可以通过维护一个生成森林来更轻松。您可以免费获得边缘添加和非树边缘删除(几乎)。对于树边删除,您可以使用BFS或DFS形式的“强力”来检查端点是否仍然连接。特别是如果节点的数量有限,也许这在实践中运行得很好,BFS和DFS对于密集图表都是O(n^2)
,你可以将一些工作收费到你幸运且没有的操作很多事情要做。
答案 1 :(得分:1)
我建议你标记所有节点。使用整数,这是最简单的。
在任何时候,你的图表将被分成许多不相交的子图。最初,每个节点都在自己的子图中。
保持每个子图具有唯一标签的条件,子图中的所有节点都带有该标签。最初,只需为每个节点提供一个唯一的标签。如果您的问题包括添加节点,您可能希望维护一个变量来保存下一个可用标签。
当且仅当新边缘连接具有相同标签的两个节点时,边缘才会创建一个循环。
每当您添加边时,您将连接两个先前不相交的子图。您必须重新标记其中一个子图以匹配另一个子图,这将需要访问一个子图的所有节点。这是该方案中最高的计算负担。
如果您不介意分配更多空间,还应该维护一个正在使用的标签列表,该标签与携带该标签的节点数相关联。这将允许您在重新标记时选择较小的子图。
答案 2 :(得分:0)
如果知道新边缘连接了哪两个节点,则可以使用某种路径查找算法来检测两个节点之间的备用路径。换句话说,如果在添加新边之前存在连接新边的两个节点的路径,则添加新边将创建一个圆。