思想:选定一个顶点,向外搜索与其他顶点相连的边的最小权值,将搜索到的顶点加入初始顶点集合,构成生成树,利用lowcost数组存储最小生成树到其他未加入生成树的点的距离,再次遍历,重复上述,直到所有点都被找到
偷了我们数据结构老师的一张图,以此来进行详解,我们以一个二维数组map来存储各点之间的距离,随意选择一个顶点出发遍历(最小生成树是为了求将图中所有顶点联通的最小距离,所以总路径长度即结果只有一个,所以节点是任选的),废话不多说,上代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define MAX 1<<20
#define M 1005
#include<iostream>
using namespace std;
int lowcost[M];//当前生成树u的集合到其他各顶点的边最短的集合
//lowcost初始为出发点到其他点的距离,不断更新为二叉树
int vis[M];//标记节点是否进入生成树,1为进入,0为无
int N;//顶点个数
int e;//边的个数
int map[M][M];//基础输入
void prim(int N,int v)//v为出发点
{
for(int i=0; i<N; i++)
{
lowcost[i]=map[v][i];//记录起点v距离其他点的距离
if(!lowcost[i])
{
lowcost[i]=MAX;
}
vis[i]=0;//初始化所有的点都没有进入二叉树
}
vis[v]=1;//很明显v进入二叉树,所以进行标记
int sum=0;//记录最短路长度,最短路数据存在lowlost数组里
int k;
int min;
int num;
for(int i=0; i<e; i++)
{
num=0;
min=MAX;//初始为最大值
for(int j=0; j<N; j++)
{
if(vis[j]==0&&lowcost[j]<min&&lowcost[j]>0)
{
min=lowcost[j];
k=j;
num++;
}
}//不断循环,知道发现与v相连的最小边,计入最短路
if(num)
{
sum+=min;
cout<<v<<"------"<<k<<"-------"<<min<<endl;
}
v=k;//此时将v更新为k,查找k的最近边
vis[k]=1;
//开始更新lowcost的数值,如果vis[j]==0;
//说明已经在此之前已经两个顶点已经联通,
//所以只遍历与出发点同属并查集但并未初始相连的点
for(int j=0; j<N; j++)
{
if(vis[j]==0&&map[v][j]<lowcost[j]&&map[v][j]>0)//此处v已经更新为新的节点,所以将其关联点距离与出发点距离各顶点做对比
{
lowcost[j]=map[v][j];
}
}
}
printf("%d\n",sum);
}
int main()
{
int zz,ww;//zz为数量,ww为路数
int u,v,cost;
int p;
while(scanf("%d%d",&zz,&ww)!=EOF)
{
memset(lowcost,0,sizeof(lowcost));
memset(vis,0,sizeof(vis));
N=zz;
e=ww;
for(int i=0; i<ww; i++)
{
scanf("%d%d%d",&u,&v,&cost);
map[u][v]=cost;
map[v][u]=cost;
}
scanf("%d",&p);
prim(N,p);
}
return 0;
}
结果如下: