【问题标题】:A fast algorithm for minimum spanning trees when edge lengths are constrained?限制边长时最小生成树的快速算法?
【发布时间】:2012-01-15 23:25:37
【问题描述】:

假设您有一个有向图,其非负整数边长在 0 到 U - 1 的范围内(包括 0 到 U - 1)。计算该图的最小生成树的最快算法是什么?我们仍然可以使用现有的最小生成树算法,例如 Kruskal 算法 O(m log n)) 或 Prim 算法 (O(m + n log n))。但是,对于 U 很小的情况,我认为应该可以做得更好。

是否有任何算法能够与更传统的 MST 算法竞争,并且能够利用边缘长度被限制在某个范围内这一事实?

谢谢!

【问题讨论】:

  • 长度是否也限制为整数,还是仅限于该范围?
  • @harold- 它们是整数。我会发布更正。
  • 几个消息来源提到有一个线性时间算法,但链接到我看不到的东西。
  • 如果边缘权重被限制为整数,你可以使用基于哈希表的优先级队列,而不是堆(或任何基于比较的O(log(n)) 样式结构)。像往常一样使用哈希队列,所有具有相同整数成本的项目都放在同一个桶中,您可以获得最坏情况下的 O(1) 操作。我认为这会从您提到的算法中删除 O(log(n)) 复杂性,留下类似 O(m + n)...
  • @DarrenEngwirda 就在这里 - 如果 U 通常很小,您可以在线性时间内进行分桶,然后通过从最低权重桶添加一条边来添加扫描,当且仅当它连接一个新顶点时.出色的(在改进和简单方面)优化。

标签: algorithm integer minimum-spanning-tree


【解决方案1】:

Fredman–Willard 给出了一个 O(m + n) 算法,用于计算单位成本 RAM 上的整数边长。

可以说这并没有太大的改进:没有对边长的限制(即,长度是只支持比较的不透明数据类型),Chazelle 给出了一个 O(m alpha(m, n) + n) 算法( alpha 是反阿克曼函数),Karger-Klein-Tarjan 给出了一个随机 O(m + n) 算法。

我认为 Darren 的想法不会导致 O(m + n + U) 时间的算法。 Jarnik(“Prim”)不会单调地使用其优先级队列,因此可能会多次扫描桶; Kruskal 需要一个不相交集的数据结构,它不可能是 O(m + n)。

【讨论】:

    【解决方案2】:

    使用整数边权重,您可以使用分桶来实现具有最坏情况 O(1) 复杂度的优先级队列,但会增加 O(U) 空间复杂度。

    在您提到的 MST 算法中,您应该能够用这个整数结构替换基于比较的优先级队列,从而消除复杂性要求中的 O(log(n)) 依赖性。我希望你最终会得到O(n + m) 风格的整体复杂性。

    本质上,您设置了一组压缩链表,其中每个列表都由与该存储桶关联的(整数!)成本进行索引:

    struct bucket_list
    {
        _cost; // array[0..N-1] holding current cost for each item
    
        _head; // array[0..U-1] holding index of first item in each bucket
    
        _next; // array[0..N-1] where _next[i] is the next item 
               // in a list for the ith item
    
        _prev; // array[0..N-1] where _prev[i] is the last item 
               // in a list for the ith item
    };
    

    这种结构是基于这样一个事实,即每个项目一次只能在一个桶列表中。

    基于此结构,您可以为这些操作实现最坏情况下的O(1) 复杂性:

    push(item, cost); // push an item onto the head of the appropriate bucket list
    
    _pop(item, cost); // _pop an item from (anywhere!) within a bucket list
    
    update(item, old_cost, new_cost); // move an item between buckets by combining
                                      // push and _pop
    

    要将此结构用作优先级队列,您只需维护一个指向当前要扫描的最小存储桶的索引。当你想获得下一个成本最低的项目时,你只需从这个桶中弹出头项目。如果存储桶为空,则增加存储桶索引,直到找到非空的。

    当然,如果U 变得非常大,则额外的空间复杂度会增加,并且项目在桶上的稀疏分布可能会使这种方法没有吸引力。

    【讨论】:

    • 这个实现的复杂性还包括 U,因为你必须遍历 O(U) 个桶。
    • 你可以说总复杂度是O(n + m + U) - 在整个算法中,桶只遍历一次,而不是每一步。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    相关资源
    最近更新 更多