【问题标题】:Second min cost spanning tree第二最小成本生成树
【发布时间】:2021-04-05 12:07:05
【问题描述】:

我正在编写一个算法来查找第二个最小成本生成树。我的想法如下:

  1. 使用 kruskals 找到最低的 MST。
  2. 删除 MST 的最低成本边。
  3. 在整个图表上再次运行 kruskals。
  4. 返回新的 MST。

我的问题是:这行得通吗?有没有更好的方法来做到这一点?

【问题讨论】:

  • 好吧,我有另一个想法......但我不太确定这是否可行......将先前避免边缘中的最小权重添加到最新的 Mst。如果我的想法是错误的。任何人都可以举个例子吗?

标签: algorithm graph


【解决方案1】:

你可以在 O(V2) 中完成。首先使用 Prim's algorithm 计算 MST(可以在 O(V2) 中完成)。

计算max[u, v] = the cost of the maximum cost edge on the (unique) path from u to v in the MST。可以在 O(V2) 内完成。

找到一个边 (u, v),它不是最小化 abs(max[u, v] - weight(u, v)) 的 MST 的一部分。可以在 O(E) == O(V2) 中完成。

返回MST' = MST - {the edge that has max[u, v] weight} + {(u, v)},这将为您提供第二好的MST。

Here's a link 到伪代码和更详细的解释。

【讨论】:

  • 感谢算法。链接失效了。
【解决方案2】:

考虑这种情况:

------100----
|           |
A--1--B--3--C
      |     |
      |     3
      |     |
      2-----D

MST 由 A-B-D-C 组成(成本 6)。第二个最小成本是 A-B-C-D(成本 7)。如果您删除成本最低的边,您将获得 A-C-B-D(成本 105)。

所以你的想法行不通。不过我没有更好的主意...

【讨论】:

  • 另外,如果最小边恰好连接了一个悬垂的顶点,删除它并再次计算 MST 甚至不会得到 MST。
【解决方案3】:

您可以这样做 - 尝试从图中一次移除一条 MST 的边,然后运行 ​​MST,从中获取最小值。所以这和你的类似,除了迭代:

  1. 使用 Kruskals 查找 MST。
  2. 对于 MST 中的每条边:
    1. 从图中删除边
    2. 在 MST 上计算 MST'
    3. 跟踪最小的 MST
    4. 将边添加回图形
  3. 返回最小的 MST。

【讨论】:

  • 谢谢。我已经列举了一些例子,这个想法似乎适用于我所有的例子。 :)
  • 这行得通 - 但与 Kruskal 的 O(NlogN) 复杂度相比,这是一个广泛的搜索,需要 O(N^2*logN)。
  • 这只是一种说法,即 MST 和 MST_2 完全不同——有比这更好的算法,但这是一种思考方式。还有 O(VE) 算法——Kruskal 实际上是 O(V log E),使得上面的 O(V^2 log E)。
  • Kruskal's 实际上是 O(E log E) 因为你正在对边缘进行排序 - 忽略不相交的集合,如果做得好,这基本上是恒定的。因此,该算法为 O(VE log E),因为您在 MST 中有 O(V) 边。所以最坏的情况是 O(V^3 log V)。 (log E = log V^2 = 2log V = O(log V))。
  • 你是对的。通常对于图形问题,我保留在 E 中,因为 log E 和 log V 是一个常数差异,但它可能指向不同的算法。我一直因为在我的答案中给出太多而被否决,我因为没有给出答案而被否决,但我知道这不是最佳选择!
【解决方案4】:

这类似于拉里的回答。

找到MST后,

对于每个 new_edge =不是 MST 中的一条边

  1. 将 new_edge 添加到 MST。
  2. 找出形成的循环。
  3. 找到权重最大的边 不是非 MST 边的循环 您添加了。
  4. 将重量增加记录为 W_Inc = w(new_edge) - w(max_weight_edge_in_cycle)。
  5. 如果 W_Inc
  6. Min_W_Inc_Seen_So_Far = W_Inc
  7. edge_to_add = new_edge
  8. edge_to_remove = max_weight_edge_in_cycle

来自以下链接的解决方案。
http://web.mit.edu/6.263/www/quiz1-f05-sol.pdf

【讨论】:

    【解决方案5】:

    稍微修改您的算法。

        Use kruskals to find lowest MST.
        for all edges i of MST
            Delete edge i of the MST.
            Run kruskals again on the entire graph.
            loss=cost new edge introduced - cost of edge i
        return MST for which loss is minimum
    

    【讨论】:

      【解决方案6】:

      这是一个计算 O(n^2) 中的第二个最小生成树的算法

      1. 首先找出最小生成树 (T)。不使用堆需要 O(n^2)。
      2. 对 T 中的每个边 e 重复。=O(n^2)
      3. 假设当前树的边缘是 e。这个树边缘会将树分成两棵树,比如说 T1 和 T-T1。 e=(u,v) 其中 u 在 T1 中,v 在 T-T1 中。 =O(n^2)

        对 T-T1 中的每个顶点 v 重复。 =O(n^2)

        为T-T1中的所有v选择边e'=(u,v),并且e'在G(原始图)中并且它是最小的

      4. 计算新形成的树的权重。比如说W=weight(T)-weight(e)+weight(e')

      5. 选择具有最小重量的T1

      【讨论】:

      • O(n^2) 是最好的吗?
      【解决方案7】:

      您的方法将不起作用,因为它可能是最小的情况。 MST 中的权重边是一座桥(只有一条边连接图的 2 个部分),因此从集合中删除这条边将产生 2 个新的 MST,而不是一个 MST。

      【讨论】:

        【解决方案8】:

        基于@IVlad 的回答

        O(V² log V)算法详解

        • 使用 Kruskal(或 Prim)算法找到最小生成树 (MST),保存其总权重,并为 MST 中的每个节点存储其树邻居(即父节点和所有子节点)-> O(V² log V)
        • 计算最小生成树中任意两个顶点之间的最大边权重。从 MST 中的每个顶点开始,使用之前计算的树节点邻居列表,使用深度或广度优先搜索遍历整个树,并存储迄今为止在每个新访问的顶点处遇到的最大边权重。 -> O(V²)
        • 求第二个最小生成树及其总权重。对于每条不属于原始 MST 的边,尝试断开它连接的两个顶点,方法是移除两个顶点之间权重最大的树边,然后将它们与当前考虑的顶点重新连接(注意:MST 应恢复为每次迭代后的原始状态)。总权重可以通过减去删除边的权重并加上添加边的权重来计算。存储获得的总权重中的最小值。

        要练习,您可以尝试竞争性编程问题UVa 10600 - ACM Contest and Blackout,该问题涉及在加权图中找到第二个最小生成树,正如 OP 所要求的那样。我的实现(在现代 C++ 中)可以在 here 找到。

        【讨论】:

          【解决方案9】:

          MST 是图的所有边的总权重最小的树。因此,第二个最小 mst 将具有图中所有边的第二个最小总权重。

          let T -> BEST_MST(对图中的边进行排序,然后使用kruskal算法找到MST)

          T ' -> 第二好的 MST

          假设 T 有 7 条边,现在要找到 T ' 我们将一一删除这 7 条边中的一条并找到该边的替代品(该边的成本肯定会大于我们刚刚从 T 中删除的边)。

          假设原始图有 15 条边

          我们最好的 MST ( T ) 有 7 条边

          第二好的 MST ( T ' ) 也将只有 7 条边

          如何找到T'

          在 T 中有 7 条边,现在对于所有这 7 条边,将它们一一移除并找到这些边的替换。

          假设 MST ( T ) 中的边 --> { a,b,c,d,e,f,g }

          假设我们的答案将是 2nd_BEST_MST,并且最初它具有无限值(我知道这听起来不太好,让我们暂时假设它)。

          对于 BEST_MST 中的所有边:

          current_edge = 我 找到那个边缘的替代品,那个边缘的替代品肯定会比第 i 个边缘(7 个边缘之一)的重量更大 我们将如何使用 Kruskul 算法找到该边的替换(我们再次找到 MST,因此我们将仅使用 kruskal 算法,但这我们不必再次对边进行排序,因为我们在找到 BEST_MST (T)。 将生成 NEW_MST 2nd_best_MST = min( NEW_MST , 2nd_best_MST ) 返回 2nd_best_MST 算法

          假设原始图有 10 条边 找到 BEST_MST(使用 kruskal 算法)并假设 BEST_MST 只有 6 条边 弓还有 4 个边缘不在 BEST_MST 中(因为它们的权重值很大,其中一个边缘将为我们提供 2nd_Best_MST 对于 BEST_MST 中不存在的每个边缘“X”(即左侧 4 个边缘),将该边缘添加到 BEST_MST 中,这将创建循环 找到循环中权重最大的边 'K' (除了 new_added_edge 'X' ) 临时删除边“K”,这将形成一个新的生成树 计算权重差异并将 weight_difference 与边缘 'X' 映射。 对所有这 4 条边重复第 4 步,并将权重差异最小的生成树返回到 BEST_MST。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-01-07
            • 2017-04-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-12-30
            • 2019-03-26
            相关资源
            最近更新 更多