【问题描述】
已知含有n个顶点(编号从1开始)的带权连通无向图,采用邻接矩阵存储,邻接矩阵以三元组的形式给出 (三元组数据结构见教材5.3.2节),只给出不包括主对角线元素在内的下三角这部分的元素,且不包括不邻接的顶点对。请采用Prim算法,求该连通图从1号顶点出发的最小生成树的权值之和。
【输入形式】
第1行给出图中结点个数n和三元组的个数num,之后每行给出一个三元组,数之间用1个空格隔开。(注意这里顶点的序号是从1到n,而不是0到n-1,程序里要小心!)
【输出形式】
求解的最小生成树的各条边、各边的权值、最小生成树的权值和
Prim算法是求解最小生成树的一种经典算法,它的主要思想可以归纳如下:从一个顶点开始,寻找与它相连的权值最小的边,把对应的顶点加入,再在所有相邻的顶点中找权值最小的边,直到覆盖了全部顶点,此时的边数为顶点数-1
首先是变量的初始化
int a[105][105]={0};
int n,m,dist[120],parent[120]={0},total;
a[105]105]就是邻接矩阵,dist[]数组用来记录每个顶点到树的距离,如果该顶点已经成为了树的一部分,则dist[i]=0,parent数组用来记录父亲节点
void prim()
{
for(int i=2;i<=n;i++)
{
parent[i]=1;
if(a[1][i])
dist[i]=a[1][i];
else
dist[i]=99999;
}
dist[1]=0;
parent[1]=-1;
while(1)
{
int v=Find();
if(v==-1)
break;
total+=dist[v];
printf("%d-%d:%d\n",parent[v],v,a[v][parent[v]]);
dist[v]=0;
for(int i=2;i<=n;i++)
{
if(dist[i]!=0&&a[i][v]<99999)
{
if(a[i][v]!=0&&a[i][v]<dist[i])
{
dist[i]=a[i][v];
parent[i]=v;
}
}
}
}
}
上面的代码段就是主要函数实现,首先先对parent数组和dist数组进行初始化,所有节点的父亲节点默认为1,初始的dist值为每个节点到节点1的权重,如果没有边相连就是无穷大,dist[1]设定为0
首先先给出我们的查找函数Find,这个函数是为了找到到已有生成树权值最小的点,如果没找到则返回-1
int Find()
{
int minv,minn=99999;
for(int i=2;i<=n;i++)
{
if(dist[i]!=0&&dist[i]<minn)
{
minn=dist[i];
minv=i;
}
}
if(minn<99999)
return minv;
else
return -1;
}
我们调用Find函数得到一个返回值v,把它的边权加入到total中,修改它的dist值为0,接下来对剩下的点进行维护,观察是否有点的dist值因为v的加入而发生改变,如果有,则及时更新。
如果我们调用Find函数返回的值为-1,那么说明已经得到了最小生成树,此时便跳出循环
下面给出完整代码
#include<bits/stdc++.h>
using namespace std;
int a[105][105]={0};
int n,m,dist[120],parent[120]={0},total;
int Find()
{
int minv,minn=99999;
for(int i=2;i<=n;i++)
{
if(dist[i]!=0&&dist[i]<minn)
{
minn=dist[i];
minv=i;
}
}
if(minn<99999)
return minv;
else
return -1;
}
void prim()
{
for(int i=2;i<=n;i++)
{
parent[i]=1;
if(a[1][i])
dist[i]=a[1][i];
else
dist[i]=99999;
}
dist[1]=0;
parent[1]=-1;
while(1)
{
int v=Find();
if(v==-1)
break;
total+=dist[v];
printf("%d-%d:%d\n",parent[v],v,a[v][parent[v]]);
dist[v]=0;
for(int i=2;i<=n;i++)
{
if(dist[i]!=0&&a[i][v]<99999)
{
if(a[i][v]!=0&&a[i][v]<dist[i])
{
dist[i]=a[i][v];
parent[i]=v;
}
}
}
}
}
int main()
{
cin>>n>>m;
for(int s=1;s<=m;s++)
{
int i,j,k;
cin>>i>>j>>k;
a[i][j]=k;
a[j][i]=k;
}
prim();
cout<<total;
return 0;
}