hiho 29 最小生成树三·堆优化的Prim算法

问题描述

最小生成树算法,在稀疏图时,Kruscal复杂度更低,我们可以使用堆优化的prim算法达到与Kruscal一样的复杂度。
Prim算法本身的时间复杂度是O(N^2)的,而在这个算法中,使用了堆来维护所有的边,操作数一共是O(M)级别的,所以复杂度是O(MlogM)的!而Kruscal算法的时间复杂度是O(MlogM + M * Ackermann’(M)),总的说来,是优化到了和Kruscal算法同样级别了呢。”

prim 算法对应于dijstra算法。dijistra算法也可以用堆进行优化。

STL中heap函数

参考这个例子中,注意push_heap 和 pop_heap只是改变vector中元素位置,并不会插入或删除元素,所以要配合vector.push_back() 和 vector.pop_back()使用!

// range heap example
#include      // std::cout
#include     // std::make_heap, std::pop_heap, std::push_heap, std::sort_heap
#include        // std::vector

int main () {
  int myints[] = {10,20,30,5,15};
  std::vector<int> v(myints,myints+5);

  std::make_heap (v.begin(),v.end());
  std::cout << "initial max heap   : " << v.front() << '\n';

  std::pop_heap (v.begin(),v.end()); v.pop_back();
  std::cout << "max heap after pop : " << v.front() << '\n';

  v.push_back(99); std::push_heap (v.begin(),v.end());
  std::cout << "max heap after push: " << v.front() << '\n';

  std::sort_heap (v.begin(),v.end());

  std::cout << "final sorted range :";
  for (unsigned i=0; istd::cout << ' ' << v[i];

  std::cout << '\n';

  return 0;
}
#include 
#include 
#include 
#include 
using namespace std;
enum {maxn = 100000+5};
struct Node{
    int a, b;
    int w;
    // 构建小顶堆
    bool operator <(const struct Node &n)const{
        return w> n.w;
    }
};
vector edge;
vector G[maxn];
bool visted[maxn];
void inline m_pop() {pop_heap(edge.begin(), edge.end()); edge.pop_back();}
void inline m_push(struct Node &n)
{
    edge.push_back(n);
    push_heap(edge.begin(), edge.end());
}
int main()
{
    //freopen("in.txt", "r", stdin);
    int N, M;
    scanf("%d %d", &N, &M);
    memset(visted, 0, sizeof(visted));
    for (int i=0; i< M; i++)
    {
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        G[a].push_back(Node{a, b, c});
        G[b].push_back(Node{b, a, c});
    }
    visted[1] = true;
    for(int i=0; i< G[1].size(); i++)
    {
        m_push(G[1][i]);
    }

    int all =0;
    int cnt = 0;
    while(cnt < N-1){
        int w = edge[0].w;
        int n = edge[0].b;
        m_pop();

        if (visted[n]){
            continue;
        }

        visted[n] = true;
        all += w;
        cnt ++;
        for (int i=0; i< G[n].size(); i++)
        {
            if (!visted[G[n][i].b])
                m_push(G[n][i]);
        }
    }
    printf("%d\n", all);
    return 0;

}

你可能感兴趣的:(hiho)