最小生成树问题

本文介绍了使用Prim和Kruskal算法求解无向图最小生成树的方法。通过定义特定的数据结构来存储图的节点与边的信息,并实现关键算法步骤,如Prim算法中的顶点集合更新和Kruskal算法中的边的排序与选择过程。此外,还提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. #include "Head.h"
  2. /*定义用于Prim算法求解最小生成树结构体:
  3. flag, 标志对应的点是否加入最小生成树(点)集合
  4. A[i][j],存放点i到点j的权重 
  5. points,记录该最小生成树的点数 */
  6. typedef struct P_Chart
  7. {
  8.     bool    *flag ;
  9.     int     **A ;
  10.     int     points ;
  11. } P_Chart ;
  12. //存放一条边的两个点
  13. typedef struct Point
  14. {
  15.     int     P1 ;
  16.     int     P2 ;
  17. } Point ;
  18. /*定义用于Kruskal算法求解最小生成树结构体:
  19. value ,记录边的权重
  20. point,存放该边的两个点
  21.  */
  22. typedef struct K_Chart
  23. {
  24.     int     value ;
  25.     Point   point ;
  26. } K_Chart ;
  27. //存放点的集合--向量
  28. typedef vector<int> Int_Vec ;
  29. //存放点集的集合--(向量的)向量
  30. typedef vector<Int_Vec> Int_Vec_Vec ;//
  31. Int_Vec_Vec     int_vec_vec ;
  32. Int_Vec     int_vec ;
  33. P_Chart     G , E ;
  34. K_Chart     *K ;
  35. int     K_i = 0 ;
  36. long    distance_P ,distance_K ;
  37. void    Print_P_Chart(const P_Chart& G ,const K_Chart *K ) ;
  38.  void Merge( K_Chart *K ,K_Chart *TR,int i,int m,int n)
  39.  { // 将有序的K1[i..m]和K1[m+1..n]归并为有序的TR[i..n] 算法10.12
  40.    int j,k,l;
  41.    for(j=m+1,k=i;i<=m&&j<=n;++k) // 将K1中记录由小到大地并入TR
  42.    {
  43.      if ( K[i].value < K[j].value )
  44.        TR[k]=K[i++];
  45.      else
  46.        TR[k]=K[j++];
  47.      
  48.    }
  49.    if(i<=m)
  50.      for(l=0;l<=m-i;l++)
  51.      {
  52.        TR[k+l]=K[i+l]; // 将剩余的K1[i..m]复制到TR
  53.        
  54.      }
  55.    if(j<=n)
  56.      for(l=0;l<=n-j;l++)
  57.      {
  58.        TR[k+l]=K[j+l]; // 将剩余的K1[j..n]复制到TR
  59.        
  60.      }
  61.  }
  62.  void MSort( K_Chart *K1 ,K_Chart *K2 ,int s, int t)
  63.  { // 将K1[s..t]归并排序为K2[s..t]。
  64.    int m;
  65.    K_Chart *TR2 = new K_Chart[K_i+1];//
  66.     //K_Chart TR2[101] ;
  67.    if(s==t)
  68.      K2[s]=K1[s];
  69.    else
  70.    {
  71.      m=(s+t)/2; // 将K1[s..t]平分为K1[s..m]和K1[m+1..t]
  72.      MSort(K1,TR2,s,m); // 递归地将K1[s..m]归并为有序的TR2[s..m]
  73.      MSort(K1,TR2,m+1,t); // 递归地将K1[m+1..t]归并为有序的TR2[m+1..t]
  74.      Merge(TR2,K2,s,m,t); // 将TR2[s..m]和TR2[m+1..t]归并到K2[s..t]
  75.    }
  76.    delete[] TR2 ;//
  77.  }
  78. void    Prim( P_Chart& G ,P_Chart& E )
  79. {/*构造最小生成树的Prim算法
  80.     输入:加权连通图 G 
  81.     输出:E ,组成 G 的最小生成树的边的集合 */
  82.     //初始化最小生成树顶点集合
  83.     G.flag[0] = true ;
  84.     for(int i=0 ;i< G.points-1 ;i++)
  85.     {
  86.         int     P1 ,P2 ;
  87.         int     min = INT_MAX ;
  88.         for(int j=1 ;j< G.points ;j++)
  89.         {           
  90.             if(G.flag[j]==false )
  91.             {
  92.                 for(int k=0 ;k< G.points ;k++)
  93.                     if(  G.flag[k]==true )//G.flag[j]==false &&
  94.                     {
  95.                         if( G.A[j][k] < min )
  96.                         {
  97.                             min = G.A[j][k] ;
  98.                             P1 = j ;
  99.                             P2 = k ;                            
  100.                         }
  101.                     }
  102.             }
  103.         }
  104.         G.flag[P1] = true ;
  105.         distance_P += E.A[P1][P2] = E.A[P2][P1] = min ;
  106.     }
  107. }
  108. //Point Find_i( int point )
  109. int     Find_i( int point )
  110. {//查找点point 在哪一个点集集合int_vec_vec的哪一个点集,
  111.     //查找成功返回该点集位置,否则返回-1
  112.     for(int i=0 ;i< int_vec_vec.size() ;i++)
  113.         for(int j=0 ;j< int_vec_vec[i].size() ;j++)
  114.         {
  115.             if( point==int_vec_vec[i][j] )
  116.             {
  117.                 //position = i ;
  118.                 return  i ;
  119.             }
  120.         }
  121.     return -1 ;
  122. }
  123. void    Print_Vec()
  124. {//输出所有点集int_vec_vec
  125.     for(int i=0 ;i< int_vec_vec.size() ;i++)
  126.     {
  127.         for(int j=0 ;j< int_vec_vec[i].size() ;j++)
  128.         {
  129.             cout << int_vec_vec[i][j] <<"  "  ;     
  130.         }
  131.         cout << endl ;
  132.     }
  133. }
  134. void    Kruskal( K_Chart *K ,P_Chart& E )
  135. {/*构造最小生成树的Kruskal算法
  136.     输入:加权连通图 K 
  137.     输出:E ,组成 G 的最小生成树的边的集合 */
  138.     for(int i=0 ;i< E.points ;i++)
  139.     {
  140.         E.flag[i] = false ;
  141.         for(int j=i ;j< E.points ;j++)
  142.         {
  143.             E.A[j][i] = E.A[i][j] = INT_MAX ;
  144.         }
  145.     }
  146.     MSort( K ,K ,0, K_i-1) ;
  147.     int     k = 0 , counter = 0 ;
  148.     int     P1 ;
  149.     int     P2 ;
  150.     do
  151.     {       
  152.         P1 = K[k].point.P1 ;
  153.         P2 = K[k].point.P2 ;
  154.         if( E.flag[P1]==false && E.flag[P2]==false
  155.         {
  156.             E.flag[P1] = true ;
  157.             E.flag[P2] = true ;
  158.             int_vec.clear() ;
  159.             int_vec.push_back(P1) ;
  160.             int_vec.push_back(P2) ;
  161.             int_vec_vec.push_back(int_vec) ;            
  162.             
  163.             counter++ ;
  164.             distance_K += E.A[P1][P2] = E.A[P2][P1] = K[k].value ;          
  165.         }
  166.         else 
  167.         {
  168.             if( E.flag[P1 ]==false || E.flag[P2]==false
  169.             {
  170.                 int     i ;
  171.                 if( E.flag[P1]==false )
  172.                 {
  173.                     E.flag[P1] = true ;
  174.                     //
  175.                     i  = Find_i(P2) ;
  176.                     int_vec_vec[i].push_back(P1) ;
  177.                 }
  178.                 else//if( E.flag[P2]==false )
  179.                 {                   
  180.                     E.flag[P2] = true ;
  181.                     //
  182.                     i  = Find_i(P1) ;
  183.                     int_vec_vec[i].push_back(P2) ;
  184.                 }
  185.                 distance_K += E.A[P1][P2] = E.A[P2][P1] = K[k].value ;
  186.                 counter++ ;
  187.             }       
  188.             else//if( E.flag[P1 ]==true && E.flag[P2]==true) 
  189.             {
  190.                 int     P1_i = Find_i(P1) ;
  191.                 int     P2_i = Find_i(P2) ;
  192.                 if(P1_i != P2_i )
  193.                 {
  194.                     if(int_vec_vec[P1_i].size() > int_vec_vec[P2_i].size() )
  195.                     {
  196.                         for(int i=0 ;i< int_vec_vec[P2_i].size() ;i++)
  197.                         {
  198.                             int_vec_vec[P1_i].push_back( int_vec_vec[P2_i][i] ) ;
  199.                         }
  200.                         int_vec_vec.erase(int_vec_vec.begin()+P2_i) ;//删除点集
  201.                     }
  202.                     else
  203.                     {
  204.                         for(int i=0 ;i< int_vec_vec[P1_i].size() ;i++)
  205.                         {
  206.                             int_vec_vec[P2_i].push_back( int_vec_vec[P1_i][i] ) ;
  207.                         }
  208.                         int_vec_vec.erase(int_vec_vec.begin()+P1_i) ;//删除点集
  209.                     }
  210.                     distance_K += E.A[P1][P2] = E.A[P2][P1] = K[k].value ;
  211.                     counter++ ;
  212.                 }   
  213.             }
  214.         }
  215.     k++ ;   
  216.     } while( counter < E.points-1 ) ;
  217.     return ;
  218. }
  219.     //为G,E ,K申请空间,且初始化、、、
  220. void    Init_P_Chart(int points)
  221. {
  222.         //为G,E ,K申请空间
  223.     G.A = new int*[points] ;
  224.     E.A = new int*[points] ;
  225.     G.flag = new bool[points] ;
  226.     E.flag = new bool[points] ;
  227.     K = new K_Chart [points*(points-1)/2] ;
  228.     
  229.     E.points = G.points = points ;
  230.     for(int i=0 ;i< points ;i++)
  231.     {
  232.         G.A[i] = new int [points] ;
  233.         E.A[i] = new int [points] ;
  234.         G.flag[i] = E.flag[i] = false ;
  235.     }
  236.     //  //为 G ,E  ,K初始化、、、
  237.     K_i = 0 ; 
  238.     for(i=0 ;i< points ;i++)
  239.         for(int j=i ;j< points ;j++)
  240.         {
  241.             E.A[j][i] = E.A[i][j] = INT_MAX ;
  242.             if( i==j )
  243.             {
  244.                 G.A[j][i] = G.A[i][j] = 0 ;
  245.                 //continue ;
  246.             }/**/
  247.             else
  248.             {
  249.                 K[K_i].value = G.A[j][i] = G.A[i][j] = rand()%20+1 ;
  250.                 K[K_i].point.P1 = i ;
  251.                 K[K_i++].point.P2 = j ;
  252.             }
  253.         
  254.         }
  255.     
  256. }
  257. //释放图的空间G ,E ,K 
  258. void    Delete_Chart(int points)
  259. {
  260.     for(int i=0 ;i< points ;i++)
  261.     {
  262.         delete[] G.A[i] ;
  263.         delete[] E.A[i] ;
  264.     }
  265.     delete[] K ;
  266.     delete[] G.A ;
  267.     delete[] E.A ;
  268. }
  269. //输出图P ,图K
  270. void    Print_P_Chart(const P_Chart& G ,const K_Chart *K )
  271. {
  272.     cout << "/n/n" ;
  273.     for(int i=0 ;i< G.points ;i++)
  274.     {
  275.         cout << "   " ;
  276.         for(int j=0 ;j< G.points ;j++)
  277.         {
  278.             if(G.A[i][j]==INT_MAX)
  279.                 cout << "∞" <<"  " ;
  280.             else
  281.                 cout << G.A[i][j] <<"  " ;
  282.         }
  283.         cout << endl ;
  284.     }   
  285.     /*
  286.     for(i=0 ;i< K_i ;i++)
  287.     {
  288.         cout << "   "<< K[i].point.P1 << " -- " << K[i].point.P2 << " :  " <<K[i].value << endl ;
  289.     }
  290.     */
  291. }
  292. void    main()
  293. {
  294.     time_t      t;
  295.     srand((unsigned) time(&t));
  296.     
  297.     char c ;
  298.     do
  299.     {       
  300.         //清空初始化
  301.         int_vec_vec.clear() ;
  302.         distance_P = 0 ;
  303.         distance_K = 0 ;
  304.         int     points ;
  305.         do
  306.         {
  307.             system("cls") ;
  308.             cout << "/n/n/n 请输入生成树的点数( > 0 ) :" ;           
  309.             cin >> points ;
  310.         } while( points <=0 ) ;
  311.         //为G,E 申请空间,且初始化、、、
  312.         Init_P_Chart( points) ;
  313.         Print_P_Chart( G ,K ) ;
  314.         Prim( G ,E ) ;//
  315.         cout << "/n 以上生成树由Prim算法求得最小生成树为(如下): " ;//
  316.         Print_P_Chart( E , K ) ;//
  317.         cout << "   以上最小生成树路径长度: " <<  distance_P << endl ;//
  318.         Kruskal( K ,E ) ;
  319.         cout << "/n 以上生成树由Kruskal算法求得最小生成树为(如下): " ;//
  320.         Print_P_Chart( E , K  ) ;
  321.         cout << "   以上最小生成树路径长度: " <<  distance_K << endl ;//
  322.         Delete_Chart(points) ;
  323.         cout << "/n/n   !!!按任意键继续,Esc退出程序!!!" << endl ;
  324.     }while( (c=getch())!=27 ) ;
  325.     return  ;
  326. }   
 ——贪婪技术在图问题中的应用
1.实验题目
    用 kruskal 算法与 prim算法构造任意一个无向图的最小生成树。 
2.实验目的
1)掌握最小生成树的概念及其基本性质;
2)掌握最优子结构性质的证明方法;
3)掌握贪心法的设计思想并能熟练运用。
3.实验要求
1)证明最小生成树满足最优子结构性质;
2)实现 kruskal与 prim算法;
3)设计测试数据,对上述两个算法进行效率比较。  
 

数据结构:

/*定义用于Prim算法求解最小生成树结构体:

flag 标志对应的点是否加入最小生成树(点)集合

A[i][j],存放点i到点j的权重

points,记录该最小生成树的点数 */

typedef    struct P_Chart

{

       bool *flag ;

       int           **A ;

       int           points ;

} P_Chart ;

//存放一条边的两个点

typedef    struct Point

{     int           P1 ;

       int           P2 ;

} Point ;

/*定义用于Kruskal算法求解最小生成树结构体:

value ,记录边的权重

point,存放该边的两个点*/

typedef    struct K_Chart

{     int           value ;

       Point       point ;

} K_Chart ;

//存放点的集合--向量

typedef    vector<int> Int_Vec ;

//存放点集的集合--(向量的)向量

typedef vector<Int_Vec>       Int_Vec_Vec ;//

 

 

 

 

函数声明:

         //GE K申请空间,且初始化、、、

void Init_P_Chart(int points)

//释放图的空间G E K

void Delete_Chart(int points)

//输出图P ,K

void Print_P_Chart(const P_Chart& G ,const K_Chart *K )

/*构造最小生成树的Prim算法

       输入:加权连通图 G

       输出:E ,组成 G 的最小生成树的边的集合 */

       //初始化最小生成树顶点集合

void Prim( P_Chart& G ,P_Chart& E )

  // K1[s..t]归并排序为K2[s..t]

void MSort( K_Chart *K1 ,K_Chart *K2 ,int s, int t)

//查找点point 在哪一个点集集合int_vec_vec的哪一个点集,

       //查找成功返回该点集位置,否则返回-1

int           Find_i( int point )

void Kruskal( K_Chart *K ,P_Chart& E )

{/*构造最小生成树的Kruskal算法

       输入:加权连通图 K

       输出:E ,组成 G 的最小生成树的边的集合 */

void Kruskal( K_Chart *K ,P_Chart& E )

{/*构造最小生成树的Kruskal算法

       输入:加权连通图 K

       输出:E ,组成 G 的最小生成树的边的集合 */

 

  // K1[s..t]归并排序为K2[s..t]

void MSort( K_Chart *K1 ,K_Chart *K2 ,int s, int t)

//查找点point 在哪一个点集集合int_vec_vec的哪一个点集,

       //查找成功返回该点集位置,否则返回-1

int           Find_i( int point )

/*构造最小生成树的Kruskal算法

       输入:加权连通图 K

       输出:E ,组成 G 的最小生成树的边的集合 */

void Kruskal( K_Chart *K ,P_Chart& E )

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值