【问题标题】:Modification of Krushkal's algorithm in O(E) time在 O(E) 时间内修改 Krushkal 算法
【发布时间】:2023-03-25 15:15:01
【问题描述】:

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

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

【问题讨论】:

  • 您找到了kruskals-algorithm 标签:为什么标题和问题中名称的拼写不同?

标签: algorithm graph kruskals-algorithm


【解决方案1】:

Kruskal 的算法是basically the following:

  • 创建一个森林 F(一组树),其中图中的每个顶点都是一棵单独的树
  • 创建一个包含图中所有边的集合 S
  • 当 S 非空且 F 尚未跨越时
    • 从 S 中移除具有最小权重的边
    • 如果移除的边连接两棵不同的树,则将其添加到森林 F,将两棵树组合成一棵树

假设您使用disjoing set data structure,成本主要由维护集合S 决定,允许最初保持所有边缘,然后找到剩余边缘中最轻的。但是,如果所有边的权重为 1 或 2,您可以使用两个链表来实现这一点,每个权重一个,每个操作将是 O(1)

【讨论】:

  • '你可以用两个链表实现这个' 怎么样?你能解释更多吗?
  • '并且每个操作都是 O(1)' 你说的是不相交集数据结构中的操作吗?
  • @AyushMishra 我指的是设置/优先队列操作。不相交集数据结构操作实际上被认为是 O(1)。
  • 如何检查两个元素是否属于同一个集合。你如何合并两个现有的集合?它们是否与使用路径压缩的原始算法相同,因为它不是 O(1)。
  • @AyushMishra 正如我之前所说,这部分是使用标准的不相交集数据结构完成的。顺便说一下,原始算法不只使用路径压缩,两个启发式的组合(压缩+按秩联合)确实有效地考虑了O(1)。
【解决方案2】:

[编辑:该算法生成 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

  1. 找到最小的边权重 x。 (如果一组不同的边权重没有作为问题的一部分给出,这可以在 O(|E|) 时间内完成,只需查看每条边。)
  2. 创建子图 G_x 的邻接表表示,它仅由权重为 x 的边和它们连接的顶点组成。这需要 O(|E|) 时间。
  3. 创建 |V(G)| 的数组 c[]值,并为所有 1
  4. 按升序循环遍历 G_x 中的所有顶点。对于任何尚未访问的顶点 v(即,对于任何具有 c[v] = v 的 v),在该顶点处开始深度优先搜索

    1. 为在 DFS 期间访问的每个顶点 u 设置 c[u] = v,并且
    2. 将每个取边附加到列表 T(请注意,T 在迭代中保留)。

    执行所有这些 DFS 需要 O(|E_x|+|V_x|) = O(|E_x|) = O(|E|) 时间,因为 G_x 的边或顶点不会被超过一个访问DFS。还要注意测试“c[v] = v?”可用于检查顶点 v 是否已被访问,而不需要像 DFS 有时需要的单独的“seen[]”数组。

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

    1. 如果 w(uv) = x,什么也不做。 (这些边缘将被丢弃。)
    2. 否则,将权重为 w(uv) 的边 (c[u], c[v]) 附加到 E'。

    这一步创建了一个新图 G' = (V, E') 的边 E',其中 G_x 中的每个连接组件都已有效地收缩到单个顶点(即组件中编号最小的顶点) ,并且所有其他边保持不变。请注意,E' 可以包含重复的边,但这不会影响正确性(DFS 可以很好地处理它们)或损害时间复杂度(因为很明显 |E'|

  6. 如果 |E'| > 0,设置 E = E' 并从第 1 步重新开始(或等效地,递归求解 E' 并将生成的边列表附加到 T)。
  7. 当我们到达这一点时,T 是 G 的最小生成 treeforest。

每一步最多花费O(|E|)时间,整个算法最多运行k次,所以在一开始给出的假设下,整体算法是O(|E|)。可以实现一些实际的加速,例如使用桶排序最初按权重对边进行排序,以及(再次通过桶排序)删除步骤 5 中生成的重复边。

【讨论】:

  • 我认为这个答案有两个问题: 1. 正如你所指出的,将其视为对 Kruskal 的修改实际上令人困惑——这正是问题所要求的。 2.根据你自己的严格标准,逆阿克曼不是 O(1),它根本不满足你所说的复杂性。许多步骤包含增长非常缓慢但并非严格恒定的指针或算术运算。
  • 对不起,你错了。单位成本 RAM 模型并不是由理论家构想出来的,他们猜测发明一个指针和算术运算的模型会很有趣。 视为 O(1)。这只是反映对于实际尺寸,这些实际上是恒定的,因此通过输入尺寸的对数来计算成本是无趣的。根据这个原理,逆阿克曼当然也是有效的常数,因为它增长得更慢。相反,在逆阿克曼不恒定的任何模型下,您的答案也不是恒定的。
  • @AmiTavory:我为 snark 道歉(有人已经删除了它,以及我的其他没有 snark 的 cmets),但是这里是你弄错了。要声称指针和算术运算是 O(1),我只需要假设单位成本 RAM 模型,它(像所有模型一样)在某些方面是不现实的。您可以挑战此模型对真实计算机的适用性/相关性,但不能挑战我的复杂性声明。 ...
  • @AmiTavory: ...相比之下,你声称 O(invAck) = O(1) 是一个更强有力的主张: O(invAck) != O(1) 是一个不依赖于任何特定计算模型的选择的数学真理,如果你要否认它,就需要你完全放弃 Big-Oh 框架。如果您仍然不相信,我鼓励您向一位受人尊敬的 CS 培训同事询问这一区别。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
相关资源
最近更新 更多