O(E)时间内Krushkal算法的修正

时间:2016-03-29 18:21:54

标签: algorithm graph kruskals-algorithm

假设G =(V,E)的边具有{1,2}的权重。修改Krushkal的算法,使其在O(E)时间内运行。

我是算法新手。这可能是什么逻辑?

2 个答案:

答案 0 :(得分:0)

Kruskal的算法是basically the following

  • 创建一个森林F(一组树),其中图中的每个顶点都是一个单独的树
  • 创建一个包含图表中所有边缘的集合
  • 而S是非空的,而F还没有跨越
    • 从S
    • 移除重量最小的边缘
    • 如果删除的边连接两个不同的树,则将其添加到森林F,将两棵树合并为一棵树

假设你正在使用disjoing set data structure,成本主要是通过维持集合 S ,允许最初保持所有边缘,然后找到最轻的剩余边缘。但是,如果所有边都具有权重1或2,则可以使用两个链接列表实现此操作,每个权重一个,每个操作将 O(1)

答案 1 :(得分:-1)

[编辑:此算法生成G的最小生成,即la Kruskal。如果连接了G,这个森林将是一棵树。]

Ami Tavory's solution在实践中会很好,并且它使用的不相交集合操作的逆Ackermann复杂度就可以在我们的物理世界中描述的任何问题上表现得像O(1),但它们不是'真正的O(1),所以整体算法不是真正的O(| E |)。

然而,如果输入是作为边列表给出的,或者作为孤立顶点的顶点的分数(或总数)是由某个常数限定的,那么一个O(| E |)算法,它实际上非常简单 - 虽然称它为“Kruskal的修改”是一个巨大的延伸,并且对于试图弄清楚它是什么的人来说非常混乱。 (注意,如果我的假设不成立 - 也就是说,如果输入没有作为边缘列表给出,并且在孤立顶点的分数上没有界限 - 那么在最坏的情况下,甚至没有算法< em>查看O(| E |)时间内的所有输入数据:G根本没有边缘,数十亿个孤立的顶点。)

算法

基本思想是重复使用DFS仅使用尚未考虑的权重最小的边来查找连接的组件,然后将这些组件折叠为单个顶点。该算法在O(k(| E | + | V |))时间内工作,其中k是输入图中不同边权重的数量 - 因此,只要上述关于输入的假设成立且k由常数限定(这里k <= 2),得到的算法是O(| E |)。我假设输入是作为边列表E给出的,但如果输入是邻接列表形式,则可以在O(| E |)时间内将其转换为此形式。

  1. 找出最小边缘重量x。 (如果没有给出一组不同的边缘权重作为问题的一部分,这可以在O(| E |)时间内完成,只需查看每个边缘。)
  2. 创建子图G_x的邻接列表表示,该表示仅包含权重x的边和它们连接的顶点。这需要O(| E |)时间。
  3. 创建| V​​(G)|的数组c []对于所有1&lt; = v&lt; = | V(G)|,设置c [v] = v。对于G_x中的顶点,c [v]将保持顶点v的“标签”,这将是包含v的G_x的连通分量中的最小编号顶点。对于顶点v不在V(G_x)中,它以后会方便地设置c [v] = v。
  4. 按递增顺序循环遍历G_x中的所有顶点。对于任何尚未访问的顶点v(即,对于任何具有c [v] = v的v),在该顶点开始深度优先搜索

    1. 为DFS期间访问过的每个顶点设置c [u] = v,
    2. 将每个获取的边追加到列表T(注意,在迭代中保留T)。
    3. 需要O(| E_x | + | V_x |)= O(| E_x |)= O(| E |)时间来执行所有这些DFS,因为没有多个访问G_x的边或顶点DFS。还要注意测试“c [v] = v?”可用于检查顶点v是否已被访问过,而不需要像DFS有时需要的单独的“seen []”数组。

    4. 创建一个空列表E'。对于原始图G中的每个边缘uv:

      1. 如果w(uv)= x,则不执行任何操作。 (这些边缘将被丢弃。)
      2. 否则,将权重w(uv)的边(c [u],c [v])追加到E'。
      3. 此步骤创建新图G'=(V,E')的边E',其中G_x中的每个连通分量已有效地缩小为单个顶点(即,组件中编号最小的顶点) ,所有其他边缘保持不变。请注意,E'可以包含重复的边,但这不会影响正确性(DFS处理它们很好)或损害时间复杂度(因为很明显| E'|&lt; = | E |)。

      4. 如果| E'| &GT; 0,设置E = E'并从步骤1重新开始(或等效地,递归以解决E'并将得到的边列表附加到T)。
      5. 当我们到达这一点时,T是G的最小跨越森林。
      6. 每个步骤最多需要O(| E |)时间,整个算法最多运行k次,因此整个算法在开始时给出的假设下为O(| E |)。有一些实际的加速可以实现,比如使用桶排序最初按重量排序边缘,并且(再次通过桶排序)删除在步骤5中生成的重复边缘。