废话
本篇博客只是复习记录所用,有任何不足之处,欢迎指出
正篇
1.自己的一些感悟
不同于Prim算法每次加入一个点,直到所有的点加入到同一集合生成一颗最小树,kruskal是每次寻找最小的边,同时记录加入的点,直到加入的点的数量和顶点数一样,本质上都是寻找先寻找拥有最小权值的边,prim是从起始点开始,而kruskal直接从边开始。
2.算法思想
3.伪代码描述
4.模拟
第一步:初始化连通分量,每一个顶点都是一个连通分量,相互独立。
第二步:从当前权值最小的边出发,找到这条边的两个顶点的同时判断这个顶点是否为一个连通分量,如果是不是连通分量,那就将两个顶点并在一起,如果是,则不用处理。最后将这条边进行标记。
接下来不断重复第二步就可以了,直到所有的边都遍历完或者顶点加入的数量和图中顶点数相同。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int Size = 100;
int parent[Size];
struct Edge
{
int from,to;
int info;
};
struct Graph
{
int vertex[Size];
Edge bian[Size];
int verNum,arcNum;
};
void Kruskal(Graph p);
int FindRoot(int parent[],int v);
main()
{
struct Graph p;
int i,j,k;
cin>>p.verNum>>p.arcNum;
for(i = 0;i < p.verNum;i ++){
p.vertex[i] = i;
}
for(i = 0;i < p.arcNum;i ++){
cin>>p.bian[i].from>>p.bian[i].to>>p.bian[i].info;
}
Kruskal(p);
return 0;
}
void Kruskal(Graph p)
{
int num,i,j,vex1,vex2,ans;
memset(parent,-1,sizeof(parent));
for(i = 0;i < p.arcNum;i ++){ //根据边集的权值由小到大排序
for(j = i;j < p.arcNum;j ++)
{
if(p.bian[i].info > p.bian[j].info)
{
Edge tem = p.bian[i];
p.bian[i] = p.bian[j];
p.bian[j] = tem;
}
}
}
for(num = 0,i = 0;i < p.arcNum;i ++)
{
vex1 = FindRoot(parent,p.bian[i].from); //找到根节点
vex2 = FindRoot(parent,p.bian[i].to);
if(vex1 != vex2) //判断是否为同一连通分量
{
cout<<"("<<p.bian[i].from<<","<<p.bian[i].to<<")"<<" ";
parent[vex2] = vex1; //将vex2的上一节点设置为 vex1
num ++;
if(num == (p.verNum - 1)) break;
}
}
}
int FindRoot(int parent[],int v) //寻找根节点
{
int t = v;
while(parent[t] != -1)
{
t = parent[t];
}
return t;
}
/*
6 10
1 2 6
1 3 1
1 4 5
2 3 5
3 4 5
2 5 3
5 3 6
3 6 4
6 4 2
5 6 6
(1,3)(3,6)(6,4)(3,2)(2,5)
*/