zoukankan      html  css  js  c++  java
  • 最小生成树(prim算法,Kruskal算法)c++实现

    1、生成树的概念 
    连通图G的一个子图如果是一棵包含G的所有顶点的树,则该子图称为G的生成树。

    生成树是连通图的极小连通子图。所谓极小是指:若在树中任意增加一条边,则将出现一个回路;若去掉一条边,将会使之变成非连通图。 生成树各边的权值总和称为生成树的权。权最小的生成树称为最小生成树。

    2、最小生成树的性质
    用哲学的观点来说,每个事物都有自己特有的性质,那么图的最小生成树也是不例外的。按照生成树的定义,n 个顶点的连通网络的生成树有 n 个顶点、n-1 条边。

    3、构造最小生成树,要解决以下两个问题:
    (1).尽可能选取权值小的边,但不能构成回路(也就是环)。
    (2).选取n-1条恰当的边以连接网的 n个顶点。

    求最小生成树的算法一般都使用贪心策略,有Prim算法和Krusal算法等。

    普里姆算法的基本思想:
    1)清空生成树,任取一个顶点加入生成树;
    2)在那些一个端点在生成树里,另一个端点不在生成树里的边中,选取一条权最小的边,将它和另一个端点加进生成树;
    3)重复步骤2,直到所有的顶点都进入了生成树为止,此时的生成树就是最小生成树。

    即:从连通网络 N = { V, E }中的某一顶点 u0 出发,选择与它关联的具有最小权值的边(u0, v),将其顶点v加入到生成树的顶点集合U中。以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u, v),把它的顶点 v加入到集合U中。如此继续下去,直到网络中的所有顶点都加入到生成树顶点集合U中为止。

     1 #include<iostream>
     2 using namespace std;
     3  
     4 #define MAX 100
     5 #define MAXCOST 0x7fffffff
     6  
     7 int graph[MAX][MAX];
     8  
     9 int Prim(int graph[][MAX], int n)//二维数组作为参数如何使用?
    10 {
    11     int sta[MAX];//存放某一条边的起点值
    12     int lowcost[MAX];//存放以i为终点的的边的最小的权值
    13     int min,minid,sum=0;//min用来存放最小权值,minid用来存放权值最小的边所对应的终点
    14     for(int i=2;i<=n;i++)
    15     {
    16         lowcost[i]=graph[1][i];//初始化lowcost[i],并把他们的初始值都看作是从节点1出发到i的权值
    17         sta[i]=1;//起点赋值为1
    18     }
    19     sta[1]=0;//节点1进入最小生成树
    20     for(int h=2;h<=n;h++)
    21     {
    22         min=MAXCOST;//找到最小的,先来个较大值
    23         for(int j=2;j<=n;j++)
    24         {
    25             if(lowcost[j]<min&&lowcost[j]!=0)//如果找到权值较小的就赋值给min,并把终点j赋值给minid。
    26             {    min=lowcost[j]; minid=j;}
    27         }
    28         lowcost[minid]=0;//这条边已经进入最小生成树,所以把值置为0
    29         sum+=min;
    30         for(int s=2;s<=n;s++)
    31         {
    32             if(lowcost[s]<graph[minid][s])//如果原先的lowcost[j]的值大于以minid为起点到终点j的权值,则更新它,并把起点更新为minid
    33             {
    34                 lowcost[s]=graph[minid][s];
    35                 sta[s]=minid;
    36             }
    37         }
    38     }
    39     return sum;
    40                
    41 }
    42 int main()
    43 {
    44    int m,n,x,y,cost;
    45    cout<<"请输入节点数目和边的数目:"<<endl;
    46    cin>>m>>n;
    47    for(int i=1;i<=m;i++)
    48        for(int j=1;j<=m;j++)
    49            graph[i][j]=MAXCOST;
    50 
    51        for(int k=1;k<=n;k++)
    52        {
    53            cin>>x>>y>>cost;
    54            graph[x][y]=graph[y][x]=cost;
    55        }
    56       cost= Prim(graph,n);
    57       cout<<cost<<endl;
    58       return 0;
    59 }

    prim函数应当好好理解,并且要多些几遍才能熟练掌握。

    Kruskal算法的步骤:

    1.对所有边进行从小到大的排序。

    2.每次选一条边(最小的边),如果如果形成环,就不加入(u,v)中,否则加入。那么加入的(u,v)一定是最佳的。

     1 #include <iostream>
     2 #include<algorithm>
     3 using namespace std;
     4  
     5 #define MAX 100
     6 struct edge 
     7 {
     8     int x,y;
     9     int w;
    10 }e[MAX];
    11 int fa[MAX];
    12 int rank[MAX];
    13 int sum;
    14 int cmp(edge a,edge b)//排序函数
    15 {
    16     if(a.w!=b.w)
    17         return a.w<b.w;
    18     else 
    19     {
    20         return a.x<b.x;
    21     }
    22 }
    23 void make_set(int x)//初始化节点
    24 {
    25   fa[x]=x;
    26   rank[x]=0;
    27 }
    28  int find(int x)//查找父节点
    29  {
    30      return fa[x]==x?x:fa[x]=find(fa[x]);
    31  }
    32 
    33 
    34  void union_set(int x,int y,int w)//合并节点
    35  {
    36      if(rank[x]>rank[y])
    37      {
    38          rank[y]=x;
    39      }
    40      else  if(rank[x]<rank[y])
    41      {
    42          rank[x]=y;
    43      }
    44      else
    45      {
    46       rank[x]++;
    47       rank[y]=x;
    48      }
    49      sum+=w;//总权值加上w
    50  }
    51 int main()
    52 {
    53     int x,y,w;
    54     int m,n;//n是点,m是边
    55     cin>>n>>m;
    56     for(int i=0;i<m;i++)
    57     {
    58         cin>>x>>y>>w;
    59         e[i].x=x;
    60         e[i].y=y;
    61         e[i].w=w;
    62         make_set(x);
    63         make_set(y);
    64     }
    65     sort(e,e+m,cmp);
    66     sum=0;
    67     for(int  i=0;i<n;i++)
    68     {
    69         x=find(e[i].x);
    70         y=find(e[i].y);
    71         w=e[i].w;
    72         if(x!=y)
    73         {
    74             union_set(x,y,w);
    75         }
    76     }
    77     cout<<sum<<endl;
    78     return 0;
    79 }

     

  • 相关阅读:
    生产环境Redis中的热点key如何发现并优化?
    一条update SQL在MySQL中结束生命历程
    主从测试过程中,如何模拟网络抖动?
    RDS-MySQL物理备份文件恢复到自建数据库
    Python从数据库中读取数据,并打印表格展示数据。
    Python简单巡检MySQL
    RDS-MySQL备份文件恢复到自建数据库
    使用Python读取Excel表格
    设计模式六大原则:迪米特法则
    设计模式六大原则:开闭原则
  • 原文地址:https://www.cnblogs.com/khbcsu/p/3873428.html
Copyright © 2011-2022 走看看