【发布时间】:2023-03-25 15:15:01
【问题描述】:
假设 G = (V,E) 的边在 {1,2} 中具有权重。修改 Krushkal 算法,使其在 O(E) 时间内运行。
我是算法的新手。这可能是什么逻辑?
【问题讨论】:
-
您找到了
kruskals-algorithm标签:为什么标题和问题中名称的拼写不同?
标签: algorithm graph kruskals-algorithm
假设 G = (V,E) 的边在 {1,2} 中具有权重。修改 Krushkal 算法,使其在 O(E) 时间内运行。
我是算法的新手。这可能是什么逻辑?
【问题讨论】:
kruskals-algorithm 标签:为什么标题和问题中名称的拼写不同?
标签: algorithm graph kruskals-algorithm
Kruskal 的算法是basically the following:
假设您使用disjoing set data structure,成本主要由维护集合S 决定,允许最初保持所有边缘,然后找到剩余边缘中最轻的。但是,如果所有边的权重为 1 或 2,您可以使用两个链表来实现这一点,每个权重一个,每个操作将是 O(1)。
【讨论】:
[编辑:该算法生成 G 的最小跨度森林,即 la Kruskal。如果 G 连通,这片森林将是一棵树。]
Ami Tavory's solution 在实践中会很好,并且它使用的不相交集运算的逆阿克曼复杂度在我们物理宇宙中可以描述的任何问题上都表现得像 O(1),但它们并不是真正的O(1),所以整个算法并不是真正的 O(|E|)。
尽管如此,如果输入是作为边列表给出的,或者如果孤立顶点的分数(或总数)受某个常数的限制,那么是 O(| E|) 算法,它实际上非常简单——尽管称其为“Kruskal 的修改”是一个巨大的延伸,对于试图弄清楚它是什么的人来说非常混乱。 (请注意,如果我在这里的假设不成立——也就是说,如果输入不是作为边列表给出的,并且孤立顶点的分数没有界限——那么在最坏的情况下,甚至没有算法可以 在 O(|E|) 时间内查看所有输入数据:G 可能根本没有边,并且有数十亿个孤立的顶点。)
基本思想是重复使用 DFS 以仅使用尚未考虑的最小权重的边找到连接的组件,然后将这些组件折叠成单个顶点。该算法在 O(k(|E|+|V|)) 时间内工作,其中 k 是输入图中不同边权重的数量——因此,只要上述关于输入的假设成立并且 k 以常数为界(这里 k
按升序循环遍历 G_x 中的所有顶点。对于任何尚未访问的顶点 v(即,对于任何具有 c[v] = v 的 v),在该顶点处开始深度优先搜索
执行所有这些 DFS 需要 O(|E_x|+|V_x|) = O(|E_x|) = O(|E|) 时间,因为 G_x 的边或顶点不会被超过一个访问DFS。还要注意测试“c[v] = v?”可用于检查顶点 v 是否已被访问,而不需要像 DFS 有时需要的单独的“seen[]”数组。
创建一个空列表 E'。对于原图G中的每条边uv:
这一步创建了一个新图 G' = (V, E') 的边 E',其中 G_x 中的每个连接组件都已有效地收缩到单个顶点(即组件中编号最小的顶点) ,并且所有其他边保持不变。请注意,E' 可以包含重复的边,但这不会影响正确性(DFS 可以很好地处理它们)或损害时间复杂度(因为很明显 |E'|
每一步最多花费O(|E|)时间,整个算法最多运行k次,所以在一开始给出的假设下,整体算法是O(|E|)。可以实现一些实际的加速,例如使用桶排序最初按权重对边进行排序,以及(再次通过桶排序)删除步骤 5 中生成的重复边。
【讨论】: