zkw神树优化dijkstra

本文介绍了如何利用ZKW线段树优化Dijkstra算法,通过添加mark标记快速定位最小值,实现O(NlgE)的时间复杂度。内容包括ZKW神树的概念、堆优化Dijkstra的分析、效率讨论及实例程序展示。
摘要由CSDN通过智能技术生成

zkw神树

zkw神树不多说了,不懂的移步我的博客《zkw线段树》。这里优化dij用,不需要区间查询,只使用点修改一个,编程复杂度极低。

唯一不同的是的为了更快找到最小值的位置(dijkstra中点的编号),需要加一个mark标记,记录最小值逻辑上的位置,或者说图里面点的编号。

奉上一个做好的zkwheap模板,不光在这里能用,是个能修改元素值的堆。

template < typename T > struct ZkwHeapNode {
  T value;
  size_t mark;
  // 编号
  ZkwHeapNode() { }
  ZkwHeapNode(const T & _value):value(_value) {}
};

template < typename T, typename Comp > class ZkwHeap {

private:
  typedef ZkwHeapNode < T > Node;
  typedef ZkwHeap < T, Comp > Heap;

  Comp cmp;
  Node *NodeList;
  size_t n;
  // 最多元素
  int init_value;
  // 初始值,大根堆(less<>)就用无穷小,小根堆(greater<>)就用无穷大

  void fix(size_t _pos) {
    if (cmp(NodeList[_pos << 1].value, NodeList[(_pos << 1) + 1].value))
      NodeList[_pos] = NodeList[(_pos << 1) + 1];
    else
      NodeList[_pos] = NodeList[_pos << 1];
  }

public:

  ZkwHeap(size_t _MaxN, const T & _init_value):init_value(_init_value) {
    n = 1 << (1 + (size_t) (log(_MaxN) / log(2.0)));
    NodeList = new Node[n << 1];
    for (size_t i = 1; i <= n + n - 1; i++)
      NodeList[i].value = init_value;
    for (size_t i = n; i <= n + n - 1; i++)
      NodeList[i].mark = i - n + 1;
     // 分配标记
  }

  ~ZkwHeap() {
    delete[]NodeList;
  }

  T top() {
    return NodeList[1].value;
  }
  // 最大元素

  T top_pos() {
    return NodeList[1].mark;
  }
  // 最大元素位置

  void modify(size_t _position, const T & _new_value) {
    int _pos = _position + n - 1;
    NodeList[_pos].value = _new_value;
    while (_pos)
      fix(_pos >>= 1);
  }

  T pop() {
    T return_value = NodeList[1].value;
    modify(NodeList[1].mark, init_value);
    return return_value;
    // 删除极值
  }
};

理解了zkw线段树,也就很容易明白为什么用zkw线段树优化dijkstra了。

堆优化dijkstra分析

dijkstra算法效率是Θ(N^2)。事实上,运用邻接表+堆优化可是将时间复杂度降到O(NlgE)。我们将在最后用聚合分析得出这个界。
为什么要堆优化?因为dijkstra最大的时间复杂度消耗在寻找dis[]中的最小值上。而用小根堆就解决了这个问题。伪代码如下:

function dijkstra(G, s) {
   
    H = a new heap
    dis = a new array contain ∞
    H中s的值设为0
    for (int i=2; i<=G.n; i++) {
        k = H中dis最小的点
        dis[k] = k.dis
        // 记录下来
        for each p connected to k {
            if (dis[
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值