假设G =(V,E)的边具有{1,2}的权重。修改Krushkal的算法,使其在O(E)时间内运行。
我是算法新手。这可能是什么逻辑?
答案 0 :(得分:0)
Kruskal的算法是basically the following:
假设你正在使用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 |)时间内将其转换为此形式。
按递增顺序循环遍历G_x中的所有顶点。对于任何尚未访问的顶点v(即,对于任何具有c [v] = v的v),在该顶点开始深度优先搜索
需要O(| E_x | + | V_x |)= O(| E_x |)= O(| E |)时间来执行所有这些DFS,因为没有多个访问G_x的边或顶点DFS。还要注意测试“c [v] = v?”可用于检查顶点v是否已被访问过,而不需要像DFS有时需要的单独的“seen []”数组。
创建一个空列表E'。对于原始图G中的每个边缘uv:
此步骤创建新图G'=(V,E')的边E',其中G_x中的每个连通分量已有效地缩小为单个顶点(即,组件中编号最小的顶点) ,所有其他边缘保持不变。请注意,E'可以包含重复的边,但这不会影响正确性(DFS处理它们很好)或损害时间复杂度(因为很明显| E'|&lt; = | E |)。
每个步骤最多需要O(| E |)时间,整个算法最多运行k次,因此整个算法在开始时给出的假设下为O(| E |)。有一些实际的加速可以实现,比如使用桶排序最初按重量排序边缘,并且(再次通过桶排序)删除在步骤5中生成的重复边缘。