最小生成树的两种算法
1.问题描述
在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无循环图,使得的 w(T) 最小,则此 T 为 G 的最小生成树
2.Prim算法
Prim算法即加点法 将一个起始点加入集合V中,寻找与集合相连并且距离最近的点加入集合,要求不可形成回路,否则舍弃此边继续寻找,重复此过程,直至所有点均加入集合
起始点 V0
加入V2
加入离集合最近的V4
加入V1
最后加入V3,所有点均加入集合,结束运算
使用parent数组记录各个点的父节点信息,当所有点均记录后这个数组就记录了最小生成树
void Prim(int point)
{
parent[point]=-1;
while(end<n) //while循环当加一个点时end+1
{
int i,j;
for(i=0;i<n;i++)
{
if(parent[i]!=-2) //当起点被访问时进行下步操作
{
for(j=0;j<n;j++)
{
if(map[i][j]<=min&&map[i][j]>0&&parent[j]==-2) //记录最短且终点未被访问的边的信息
{
min1=i;
min2=j;
min=map[i][j];
}
}
}
}
parent[min2]=min1; //加入最小生成树
end++;
min=1e5;
}
}
3.Kruskal算法
Kruskal算法即加边法 将边从小到大排序,从最小的边开始访问,在不形成闭环的情况下,将边先生成森林,再将森林连成一棵树
int kruskal()
{
int i;
for(i=0;i<pn;i++)
{
v[i]=i;
}
int num=pn;
for(i=0;i<en&&num>1;i++)
{
int p1=getroot(m[i].point1);
int p2=getroot(m[i].point2);
if(p1!=p2)
{
v[p1]=p2;
num--;
}
}
for(i=0;i<en;i++)
{
if(v[m[i].point1]!=m[i].point1)
printf("%d-%d\n",m[i].point1,m[i].point2);
}
}
4.源码
github:
https://github.com/1651928813/Pepsi_juice