Prim法求最小生成树
Prim求最小生成树
算法思想:
此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。
在图G(V,E)中,V是该图的所有顶点的集合,E是该图中所有边的集合
1.图中所有顶点的集合为V,初始时令U={s},其中s是放入U的第一个顶点,随机选一个即可,T=V-U是未放入到集合的顶点的集合
2.在两个集合U和T所组成的边中,选择代价最小的边,并入集合U中。
3.重复上述步骤,直到U中有n个顶点为止,算法结束。
在这个算法中我们需要辅助数组来记录顶点U到T中的权最小的边
struct closedge
{
int adjvex;//最小边在U上的那个顶点
int lowcost;//记录最小边上的权值
};
实现算法:
Ps: 1.此算法输入的为完全图,也可以改成任意条边的图,只需改createGraphy()方法即可
2.图的最大顶点数n<=100,顶点标号从0~n-1
3.权值不能为负数
/**
* prim方法生成最小生成树 2018-7-2-16:05
**/
#include <iostream>
#define inf 99999
using namespace std;
//生成邻接矩阵来存储U到V-U集合中的顶点的信息
struct closedg
{
int adjvex;//最小边在u中的的顶点
int lowcost;//最小边上的权值
};
int ch[100][100];
struct closedg closedge[100];//邻接矩阵
int book[100]={0};//用来记录U中的顶点数
/**
*创建完全图
**/
void createGraphy(int n)
{ int m=n*(n-1)/2;
int a,b,value;
cout<<"输入边的顶点和权值:"<<endl;
for(int i=0;i<m;i++)
{
cin>>a>>b>>value;
ch[a][b]=value;
ch[b][a]=value;
}
for(int i=0;i<n;i++)
ch[i][i]=inf;
}
/**
*返回最小的那个顶点
**/
int FindMinPoint(int n)
{ int index,min=inf;
for(int i=0;i<n;i++)
{
if(book[i]==0&&closedge[i].lowcost<min)
{
index=i;
min=closedge[i].lowcost;
}
}
return index;
}
/**
*利用prim算法思想创建最小生成树,这里我们将编号为0的顶点最先放到
*U中
**/
void MinTree_Prim(int n)
{
book[0]=1;
//更新closeedge
for(int i=0;i<n;i++)
{
closedge[i].adjvex=0;
closedge[i].lowcost=ch[0][i];
}
//进行n-1次循环,因为V-U中有n-1个顶点
for(int j=0;j<n-1;j++)
{
int lowindex=FindMinPoint(n);
book[lowindex]=1;
//更新lowcost
for(int i=0;i<n;i++)
{
if(book[i]==0&&closedge[i].lowcost>ch[lowindex][i])
{
closedge[i].adjvex=lowindex;
closedge[i].lowcost=ch[lowindex][i];
}
}
}
}
void PrintMinTree(int n)
{ char c[]={'a','b','c','d','e','f'};
for(int i=1;i<n;i++)
cout<<c[i]<<"--"<<c[closedge[i].adjvex]<<endl;
}
int main()
{
int n;
cout<<"请输入顶点数:"<<endl;
cin>>n;
createGraphy(n);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
cout<<ch[i][j]<<' ';
cout<<endl;
}
MinTree_Prim(n);
PrintMinTree(n);
}
测试数据:
我从参考资料的那个博客中搜取的数据输出结果正确