首页 > 代码库 > 最小生成树(prim算法,Kruskal算法)c++实现

最小生成树(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;//起点赋值为118     }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[j]=0;//这条边已经进入最小生成树,所以把值置为029         sum+=min;30         for(int s=2;s<=n;s++)31         {32             if(lowcost[s]<graph[minid][s])//如果原先的lowcost[j]的值大于以minid为起点到终点j的权值,则更新它,并把起点更新为minid33             {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      else45      {46       rank[x]++;47       rank[y]=x;48      }49      sum+=w;//总权值加上w50  }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 }