最小生成树

最小生成树

http://blog.csdn.net/huangxy10/article/details/8046131#t0

 设G = (V,E)是无向连通带权图,即一个网络。E中的每一条边(v,w)的权为c[v][w]。如果G的子图G’是一棵包含G的所有顶点的树,则称G’为G的生成树。生成树上各边权的总和称为生成树的耗费。在G的所有生成树中,耗费最小的生成树称为G的最小生成树。构造最小生成树的两种方法:Prim算法和Kruskal算法

  一、最小生成树的性质

  设G = (V,E)是连通带权图,U是V的真子集。如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中,(u,v)的权c[u][v]最小,那么一定存在G的一棵最小生成树,它意(u,v)为其中一条边。这个性质有时也称为MST性质。

  二、Prim算法

  设G = (V,E)是连通带权图,V = {1,2,…,n}。构造G的最小生成树Prim算法的基本思想是:首先置S = {1},然后,只要S是V的真子集,就进行如下的贪心选择:选取满足条件i ∈S,j ∈V – S,且c[i][j]最小的边,将顶点j添加到S中。这个过程一直进行到S = V时为止。在这个过程中选取到的所有边恰好构成G的一棵最小生成树。

如下带权图:

生成过程

1 -> 3 : 1

3 -> 6 : 4

6 -> 4: 2

3 -> 2 : 5

2 -> 5 : 3

 prim算法的演示如下:

  1. /* 主题:贪心算法——最小生成树(Prim) 
  2. * 作者:chinazhangjie 
  3. * 邮箱:chinajiezhang@gmail.com 
  4. * 开发语言: C++ 
  5. * 开发环境: Virsual Studio 2005 
  6. * 时间: 2010.11.30 
  7. */  
  8.   
  9. #include <iostream>  
  10. #include <vector>  
  11. #include <limits>  
  12. using namespace std ;  
  13.   
  14. struct TreeNode  
  15. {  
  16. public:  
  17.     TreeNode (int nVertexIndexA = 0, int nVertexIndexB = 0, int nWeight = 0)  
  18.         : m_nVertexIndexA (nVertexIndexA),  
  19.         m_nVertexIndexB (nVertexIndexB),  
  20.         m_nWeight (nWeight)  
  21.     { }  
  22. public:  
  23.     int m_nVertexIndexA ;  
  24.     int m_nVertexIndexB ;  
  25.     int m_nWeight ;  
  26. } ;  
  27.   
  28. class MST_Prim  
  29. {  
  30. public:  
  31.     MST_Prim (const vector<vector<int> >& vnGraph)   
  32.     {  
  33.         m_nvGraph = vnGraph ;  
  34.         m_nNodeCount = (int)m_nvGraph.size () ;  
  35.     }  
  36.     void DoPrim ()  
  37.     {  
  38.         // 是否被访问标志  
  39.         vector<bool> bFlag (m_nNodeCount, false) ;  
  40.         bFlag[0] = true ;  
  41.   
  42.         int nMaxIndexA ;  
  43.         int nMaxIndexB ;  
  44.         int j = 0 ;  
  45.         while (j < m_nNodeCount - 1) {  
  46.             int nMaxWeight = numeric_limits<int>::max () ;  
  47.             // 找到当前最短路径  
  48.             int i = 0 ;  
  49.             while (i < m_nNodeCount) {  
  50.                 if (!bFlag[i]) {  
  51.                     ++ i ;  
  52.                     continue ;  
  53.                 }  
  54.                 for (int j = 0; j < m_nNodeCount; ++ j) {  
  55.                     if (!bFlag[j] && nMaxWeight > m_nvGraph[i][j]) {  
  56.                         nMaxWeight = m_nvGraph[i][j] ;  
  57.                         nMaxIndexA = i ;  
  58.                         nMaxIndexB = j ;  
  59.                     }   
  60.                 }  
  61.                 ++ i ;  
  62.             }  
  63.             bFlag[nMaxIndexB] = true ;  
  64.             m_tnMSTree.push_back (TreeNode(nMaxIndexA, nMaxIndexB, nMaxWeight)) ;  
  65.             ++ j ;  
  66.         }  
  67.         // 输出结果  
  68.         for (vector<TreeNode>::const_iterator ite = m_tnMSTree.begin() ;  
  69.                 ite != m_tnMSTree.end() ;  
  70.                 ++ ite ) {  
  71.             cout << (*ite).m_nVertexIndexA << "->"   
  72.                 << (*ite).m_nVertexIndexB << " : "  
  73.                 << (*ite).m_nWeight << endl ;  
  74.         }  
  75.     }  
  76. private:  
  77.     vector<vector<int> > m_nvGraph ;    // 无向连通图  
  78.     vector<TreeNode>    m_tnMSTree ;    // 最小生成树  
  79.     int    m_nNodeCount ;  
  80. } ;  
  81.   
  82. int main()  
  83. {  
  84.     const int cnNodeCount = 6 ;  
  85.     vector<vector<int> > graph (cnNodeCount) ;  
  86.     for (size_t i = 0; i < graph.size() ; ++ i) {  
  87.         graph[i].resize (cnNodeCount, numeric_limits<int>::max()) ;  
  88.     }  
  89.     graph[0][1]= 6 ;  
  90.     graph[0][2] = 1 ;  
  91.     graph[0][3] = 5 ;  
  92.     graph[1][2] = 5 ;  
  93.     graph[1][4] = 3 ;  
  94.     graph[2][3] = 5 ;  
  95.     graph[2][4] = 6 ;  
  96.     graph[2][5] = 4 ;  
  97.     graph[3][5] = 2 ;  
  98.     graph[4][5] = 6 ;  
  99.       
  100.     graph[1][0]= 6 ;  
  101.     graph[2][0] = 1 ;  
  102.     graph[3][0] = 5 ;  
  103.     graph[2][1] = 5 ;  
  104.     graph[4][1] = 3 ;  
  105.     graph[3][2] = 5 ;  
  106.     graph[4][2] = 6 ;  
  107.     graph[5][2] = 4 ;  
  108.     graph[5][3] = 2 ;  
  109.     graph[5][4] = 6 ;  
  110.   
  111.     MST_Prim mstp (graph) ;  
  112.     mstp.DoPrim () ;  
  113.      return 0 ;  
  114. }  

 三、Kruskal算法

  当图的边数为e时,Kruskal算法所需的时间是O(eloge)。当e = Ω(n^2)时,Kruskal算法比Prim算法差;但当e = o(n^2)时,Kruskal算法比Prim算法好得多

给定无向连同带权图G = (V,E),V = {1,2,...,n}。Kruskal算法构造G的最小生成树的基本思想是:

1)首先将G的n个顶点看成n个孤立的连通分支。将所有的边按权从小大排序。

(2)从第一条边开始,依边权递增的顺序检查每一条边。并按照下述方法连接两个不同的连通分支:当查看到第k条边(v,w)时,如果端点v和w分别是当前两个不同的连通分支T1和T2的端点是,就用边(v,w)将T1和T2连接成一个连通分支,然后继续查看第k+1条边;如果端点v和w在当前的同一个连通分支中,就直接再查看k+1条边。这个过程一个进行到只剩下一个连通分支时为止。

此时,已构成G的一棵最小生成树。


Kruskal算法的选边过程

1 -> 3 : 1

4 -> 6 : 2

2 -> 5 : 3

3 -> 4 : 4

2 -> 3 : 5

  1. /* 主题:贪心算法之最小生成树(Kruskal算法) 
  2. * 作者:chinazhangjie 
  3. * 邮箱:chinajiezhang@gmail.com 
  4. * 开发语言:C++ 
  5. * 开发环境:Visual Studio 2005 
  6. * 时间:2010.12.01 
  7. */  
  8.   
  9. #include <iostream>  
  10. #include <vector>  
  11. #include <queue>  
  12. #include <limits>  
  13. using namespace std ;  
  14.   
  15. struct TreeNode  
  16. {  
  17. public:  
  18.     TreeNode (int nVertexIndexA = 0, int nVertexIndexB = 0, int nWeight = 0)  
  19.         : m_nVertexIndexA (nVertexIndexA),  
  20.         m_nVertexIndexB (nVertexIndexB),  
  21.         m_nWeight (nWeight)  
  22.     { }  
  23.     friend   
  24.     bool operator < (const TreeNode& lth, const TreeNode& rth)   
  25.     {  
  26.         return lth.m_nWeight > rth.m_nWeight ;  
  27.     }  
  28.   
  29. public:  
  30.     int m_nVertexIndexA ;  
  31.     int m_nVertexIndexB ;  
  32.     int m_nWeight ;  
  33. } ;  
  34.   
  35. //  并查集  
  36. class UnionSet   
  37. {  
  38. public:  
  39.     UnionSet (int nSetEleCount)  
  40.         : m_nSetEleCount (nSetEleCount)  
  41.     {  
  42.         __init() ;  
  43.     }  
  44.     // 合并i,j。如果i,j同在集合中,返回false。否则返回true  
  45.     bool Union (int i, int j)  
  46.     {  
  47.         int ifather = __find (i) ;  
  48.         int jfather = __find (j) ;  
  49.         if (ifather == jfather )  
  50.         {  
  51.             return false ;  
  52.             // copy (m_nvFather.begin(), m_nvFather.end(), ostream_iterator<int> (cout, " "));  
  53.             // cout << endl ;  
  54.         }  
  55.         else  
  56.         {  
  57.             m_nvFather[jfather] = ifather ;  
  58.             // copy (m_nvFather.begin(), m_nvFather.end(), ostream_iterator<int> (cout, " "));  
  59.             // cout << endl ;  
  60.             return true ;  
  61.         }  
  62.           
  63.     }  
  64.   
  65. private:  
  66.     // 初始化并查集  
  67.     int __init()  
  68.     {  
  69.         m_nvFather.resize (m_nSetEleCount) ;  
  70.         for (vector<int>::size_type i = 0 ;  
  71.             i < m_nSetEleCount;  
  72.             ++ i )  
  73.         {  
  74.             m_nvFather[i] = static_cast<int>(i) ;  
  75.             // cout << m_nvFather[i] << " " ;  
  76.         }  
  77.         // cout << endl ;  
  78.         return 0 ;  
  79.     }  
  80.     // 查找index元素的父亲节点 并且压缩路径长度   
  81.     int __find (int nIndex)  
  82.     {  
  83.         if (nIndex == m_nvFather[nIndex])  
  84.         {  
  85.             return nIndex;  
  86.         }  
  87.         return  m_nvFather[nIndex] = __find (m_nvFather[nIndex]);  
  88.     }  
  89.   
  90. private:  
  91.     vector<int>                m_nvFather ;    // 父亲数组  
  92.     vector<int>::size_type m_nSetEleCount ;    // 集合中结点个数  
  93. } ;  
  94.   
  95. class MST_Kruskal  
  96. {  
  97.     typedef priority_queue<TreeNode> MinHeap ;  
  98. public:  
  99.     MST_Kruskal (const vector<vector<int> >& graph)   
  100.     {  
  101.         m_nNodeCount = static_cast<int>(graph.size ()) ;  
  102.         __getMinHeap (graph) ;  
  103.     }  
  104.     void DoKruskal ()  
  105.     {  
  106.         UnionSet us (m_nNodeCount) ;  
  107.         int k = 0 ;   
  108.         while (m_minheap.size() != 0 && k < m_nNodeCount - 1)   
  109.         {  
  110.             TreeNode tn = m_minheap.top () ;  
  111.             m_minheap.pop () ;  
  112.             // 判断合理性  
  113.             if (us.Union (tn.m_nVertexIndexA, tn.m_nVertexIndexB))   
  114.             {  
  115.                 m_tnMSTree.push_back (tn) ;  
  116.                 ++ k ;  
  117.             }  
  118.         }  
  119.         // 输出结果  
  120.         for (size_t i = 0; i < m_tnMSTree.size() ; ++ i)   
  121.         {  
  122.             cout << m_tnMSTree[i].m_nVertexIndexA << "->"  
  123.                 << m_tnMSTree[i].m_nVertexIndexB << " : "  
  124.                 << m_tnMSTree[i].m_nWeight   
  125.                 << endl ;  
  126.         }  
  127.     }  
  128.   
  129. private:  
  130.     void __getMinHeap (const vector<vector<int> >& graph)   
  131.     {  
  132.         for (int i = 0; i < m_nNodeCount; ++ i)   
  133.         {  
  134.             for (int j = 0; j < m_nNodeCount; ++ j)   
  135.             {  
  136.                 if (graph[i][j] != numeric_limits<int>::max())   
  137.                 {  
  138.                     m_minheap.push (TreeNode(i, j, graph[i][j])) ;  
  139.                 }  
  140.             }  
  141.         }  
  142.     }  
  143. private:  
  144.     vector<TreeNode>    m_tnMSTree ;  
  145.     int                    m_nNodeCount ;  
  146.     MinHeap                m_minheap ;  
  147. } ;  
  148.   
  149.   
  150. int main ()  
  151. {  
  152.     const int cnNodeCount = 6 ;  
  153.     vector<vector<int> > graph (cnNodeCount) ;  
  154.     for (size_t i = 0; i < graph.size() ; ++ i)   
  155.     {  
  156.         graph[i].resize (cnNodeCount, numeric_limits<int>::max()) ;  
  157.     }  
  158.     graph[0][1]= 6 ;  
  159.     graph[0][2] = 1 ;  
  160.     graph[0][3] = 3 ;  
  161.     graph[1][2] = 5 ;  
  162.     graph[1][4] = 3 ;  
  163.     graph[2][3] = 5 ;  
  164.     graph[2][4] = 6 ;  
  165.     graph[2][5] = 4 ;  
  166.     graph[3][5] = 2 ;  
  167.     graph[4][5] = 6 ;  
  168.       
  169.     graph[1][0]= 6 ;  
  170.     graph[2][0] = 1 ;  
  171.     graph[3][0] = 3 ;  
  172.     graph[2][1] = 5 ;  
  173.     graph[4][1] = 3 ;  
  174.     graph[3][2] = 5 ;  
  175.     graph[4][2] = 6 ;  
  176.     graph[5][2] = 4 ;  
  177.     graph[5][3] = 2 ;  
  178.     graph[5][4] = 6 ;  
  179.   
  180.     MST_Kruskal mst (graph);  
  181.     mst.DoKruskal () ;  
  182. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值