最小生成树

Posted 鄉勇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小生成树相关的知识,希望对你有一定的参考价值。

最小生成树

Prim

时间复杂度O(n2)

蓝白点思想,蓝点代表为纳入最小生成树的点,白点代表已纳入的点。

初始化所有点到最小生成树的距离;(极大值)

选择一个点作为树的根节点;(没有要求的话,一般选择第一个点)

枚举该点出发的所有边,进行松弛操作,并将该点标为白色;

从蓝点中选取离最小生成树最近的点进行松弛操作,并加入最小生成树;

如此循环,直到所有点都加入最小生成树;

例题:【模板】最小生成树

算法结束。

复制代码
#include<cstdio>
#include<iostream>
using namespace std;
const int inf=100000000;
int n,ans,p,b;
int a[110],map[110][110];
bool v[110];
int main(){
    scanf("%d",&n); 
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    scanf("%d",&map[i][j]);
    for(int i=1;i<=n;i++) a[i]=map[1][i];
    v[1]=1;
    for(int i=1;i<n;i++){
        p=inf;
        for(int i=1;i<=n;i++) if(!v[i]&&a[i]<p){p=a[i];b=i;}
        ans+=a[b];v[b]=1;
        for(int i=1;i<=n;i++) a[i]=min(a[i],map[b][i]);
    }
    printf("%d\\n",ans);
    return 0;
}
复制代码

 

Kruskal

时间复杂度O(eloge)

加边法。

首先,对所有边进行排序,时间复杂度O(eloge);

从小到大枚举边,如果边的两端已经处于同一个集合,加入该边,否则不加入。

复制代码
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 int n,m,a,b,ans;
 5 int fa[5010];
 6 struct nate{
 7     int q,z,bq;
 8 }edge[200010];
 9 int comp(const nate&x,const nate&y ){return x.bq<y.bq;}
10 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
11 int main(){
12     scanf("%d%d",&n,&m);
13     for(int i=1;i<=m;i++) scanf("%d%d%d",&edge[i].q,&edge[i].z,&edge[i].bq);
14     sort(edge+1,edge+m+1,comp);
15     for(int i=1;i<=n;i++) fa[i]=i;
16     for(int i=1;i<=m;i++){
17         a=find(edge[i].q);b=find(edge[i].z);
18         if(a!=b){
19             ans+=edge[i].bq;
20             fa[b]=a;
21         }
22     }
23     printf("%d\\n",ans);
24     return 0;
25 }
复制代码

 

从时间复杂度来看,两种算法各有优劣,不过在OI中,一般的图都是点多边少,所以Kruskal可能更常用一些;

以上是关于最小生成树的主要内容,如果未能解决你的问题,请参考以下文章

最小生成树matlab代码Kruskal算法,用于二维网络生成

c语言最小生成树

最小生成树及Prim算法及Kruskal算法的代码实现

数据结构 图连通与最小生成树

次最小生成树 模版

图的最小生成树算法(图解+代码)| 学不会来看我系列