最小生成树之Prim算法

Prim算法的流程为,首先从任意一个节点出发,逐渐生成,直至该树覆盖了所有的V中的节点。

如下图:


图中的黑色的边即是最小生成树中的边。

实现Prim算法的关键是如何选择一条 “权值较小并且对于已有生成树中的点集合S来说是安全的边”,此处的安全指的是:

加入该边e之后,S仍然是一个树。

于是:对于图 G = (V, E) Prim的执行步骤大致为:

1   从 任意节点s 开始,因此将原来的顶点集合分为两部分: S = {s},  T = V- S =  V  - {s},

2   计算T中的节点到S中的节点的距离,即对于T中的节点v而言, d(v) = min{(u,v), u 属于S };

3   选出所有的(2)中的计算的最短的权,加入到S中,并且更新S与T中的点的集合。

4   重复2,3步,直至所有的节点都在S中,T为空。

执行完毕。


上述的步骤可由下面的简单的图解来解释:

因此最终的结果是17.

上述最重要的便是记录不在S中的节点到S中的最短的距离。这显然可以使用优先队列(堆)来实现,但是在选中该点之后,需要更新它的邻居节点的距离信息,即会减小队列中的key值,这是优先队列没有实现的,于是我自行实现了一个最小堆,并且实现了Prim算法,代码如下:

//Heap

#ifndef _HEAP_H
#define _HEAP_H

#include 
   
   
    
    
using namespace std;

typedef pair
    
    
     
       Elem;

struct cmp:public binary_function
     
     
      
      
{
  bool operator()(const Elem &lhs, const Elem &rhs)
  {
      return lhs.second > rhs.second;
  }
};

class Heap
{
  private:
    vector
      
      
       
        content;
    
  public:
    Heap(){}
    template
       
       
         Heap(InputIterator beg, InputIterator end) { content.assign(beg,end); make_heap(content.begin(), content.end(), cmp()); } void push(const Elem &x) { content.push_back(x); push_heap(content.begin(),content.end(),cmp()); } void pop() { pop_heap(content.begin(),content.end(),cmp()); content.pop_back(); } void decreaseKey(int key, int value) { auto idx = find_if(content.begin(), content.end(), [& key](const Elem & x){return key==x.first;}); if(idx==content.end()) { cout << "error : input illegal!!" << endl; return; } if((*idx).second <= value) { return; } (*idx).second=value; push_heap(content.begin(), idx+1,cmp()); } bool empty() const { return content.empty(); } Elem min() const { if(empty()) throw runtime_error("empty heap..."); return content[0]; } }; #endif /*_HEAP_H*/ //Prim void Prim(int start) { Heap h; //record the cost of each node int min_cost[V]; fill_n(min_cost, V,100); //record the node is in the MST or not bool used[V]; fill_n(used,V,false); //record the prev node inserted to the MST bool parent[V]; fill_n(parent,V,false); int total_cost=0; //record cost used[start] = true; min_cost[start]=0; h.push(make_pair(0,0)); for(int i=1;i 
        
          < G[cur].size();++i) { int adj = G[cur][i]; if(used[adj] == false && min_cost[adj] > cost[cur][adj]) { h.decreaseKey(adj,cost[cur][adj]); parent[adj] = cur; min_cost[adj]=cost[cur][adj]; } } } cout << "MST =" << total_cost << endl; } 
         
       
      
      
     
     
    
    
   
   



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值