假设您有一个非负整数边长的有向图,其范围在0到U-1之间。计算此图的最小生成树的最快算法是什么?我们仍然可以使用现有的最小生成树算法,例如Kruskal算法O(m log n))或Prim算法(O(m + n log n))。但是,对于U很小的情况,我认为应该可以做得更好。
是否有任何算法可以与更传统的MST算法竞争,这些算法能够利用边长被限制在某个范围内的事实?
谢谢!
答案 0 :(得分:8)
Fredman-Willard在单位成本RAM上给出了整数边长的O(m + n)算法。
可以说没有太大的改进:没有边长的限制(即长度是仅支持比较的不透明数据类型),Chazelle给出了O(m alpha(m,n)+ n)算法( alpha是逆Ackermann函数),Karger-Klein-Tarjan给出了随机O(m + n)算法。
我不认为Darren的想法会导致O(m + n + U)时间算法。 Jarnik(“Prim”)不单调使用其优先级队列,因此可以多次扫描存储桶; Kruskal需要一个不相交的数据结构,不能是O(m + n)。
答案 1 :(得分:3)
使用整数边缘权重,您可以使用bucketing来实现具有最差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
变得非常大,额外的空间复杂性,以及在桶上稀疏分布项目的可能性可能会使这种方法没有吸引力。