Prim:Prim实际上与最短路的Dij,Bellman-ford类似,都是运用蓝白点的思维.开一个bool数组白点(0)表示未进入最小生成树的点.蓝点(1)表示已进入最小生成树的点.
Prim算法与Dij一样,不能够处理负边权的情况(思维与贪心类似).
先初始化 :min[i]=无穷大,表示以1为起点的最小生成树蓝点(i)与白点连接的最小边权.min[1]=0,表示以1为起点,边权为0,之后ans=0.
计算:for(i=1;i<=n;i++)
寻找min[x]最小的x,把x标记为白点,ans+=min[x];最后再次寻找与白点x相连的所有蓝点,一次结束.
两层循环,第一层枚举n个点,第二层查找蓝点与白点,时间复杂度O(n^2).
Kruskal:Kruscal与Prim思维不太相同,需要用到并查集+链表。首先需要把相互连通的一些点放入同一连通块中.
先初始化:father[i]=i;(可以用路径压缩与启发式合并,这样并查集时间复杂度可以变成O(n).
再写链表,我比较愿意用结构体(也可以不用).
head[i]表示i前面的点是谁,edge[i].to表示到达谁,edge[i].next表示下一个点是谁,edge[i].value表示边权是多少.数组一定要开边的2倍,因为存的是双向边.
把idx先置成0.
void addedge(int a,int b,int c)
{
edge[++idx].next=head[a];
head[a]=idx;
edge[idx].to=b;
edge[idx].value=c;
}
之后调用两遍函数就存进来了.
并查集这里就不详细说了,等总结到并查集时再说.
ans=0;
之后所有边的权值从小到大排序(sort)即edge[i].value.
这里就是要用并查集的时刻,判断这条边是否在并查集中,如果在,就不用加入最小生成,如果不在,就加入.
ans+=edge[i].value;
每加入一条边,层数+1,如果层数=n-1,表示最小生成树已生成,结束.
一共E条边,sort排序O(ElogE),并查集O(n),总:ElogE.
总结:看情况选择Prim与Kruskal两种算法,在稀疏图中(E接近n时),Kruskal可以达到O(nlogn),但是在稠密图中(E接近n^2时),Kruskal为O(n^2logn),不如Prim.这种时间复杂度如果非要用Kruskal做的话可以直接用邻接矩阵.
这是博主第一篇文章,有问题可以尽情评论,感谢大家的支持.