什么是最小生成树(MST)?
给定一个带权的无向连通图,选取一棵生成树(原图的极小连通子图),使生成树上所有边上权的总和为最小,称为该图的最小生成树。
求解最小生成树的算法一般有这两种:Prim算法和Kruskal算法。
Prim算法(普里姆算法)
图的存贮结构采用邻接矩阵。此方法是按各个顶点连通的步骤进行,需要用一个顶点集合,开始为空集,以后将以连通的顶点陆续加入到集合中,全部顶点加入集合后就得到所需的最小生成树。
简单描述:
1.初始化:Vnew = {x},其中x为集合V中的任一节点(作为起始点),Enew = {},为空。
2.在边集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一)。将v加入集合Vnew中,将<u, v>边加入集合Enew中。
3.重复操作2直至Vnew = V。
代码展示:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int INF=0x3f3f3f3f; const int N=101; int G[N][N];//邻接矩阵 int Lowest[N];//表示和已选顶点集Vnew的最小距离,Lowest[i]=0表示点i已经在Vnew中 int n,m; int prim() { int Num=0;//最小生成树权值 for(int i=2;i<=n;i++)//选取第一个点开始 Lowest[i]=G[1][i];//取第一行权值 for(int i=1;i<n;i++)//找到新顶点加入(n-1个) { int minid=0; int mindis=INF; for(int j=2;j<=n;j++)//找到距离最小的 { if(Lowest[j]!=0&&Lowest[j]<mindis) { mindis=Lowest[j]; minid=j; } } Num+=mindis; Lowest[minid]=0;//把点minid加入Vnew for(int j=2;j<=n;j++)//更新Lowest数组 if(Lowest[j]>G[minid][j]) Lowest[j]=G[minid][j]; } return Num; } int main() { while(~scanf("%d%d",&n,&m)) { memset(G,0x3f,sizeof(G));//初始化为最大值 for(int i=1;i<=n;i++)//对角线为0 G[i][i]=0; int u,v,w; for(int i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&w); G[u][v]=G[v][u]=w; } int MST=prim();//计算最小生成树总权值 printf("%d\n",MST); } }