最小生成树算法


f i r s t 最 小 生 成 树 first 最小生成树 first

 最小生成树指的是在一个边有权的树上,求一个边权和最小的树形结构,并且使得这个树形结构要覆盖这个边上的所有点。现在求最小生成树的算法主要有两种,一个是 p r i m e prime prime 算法,一个是 K r u s k a l Kruskal Kruskal 算法。

一 prime算法

1.定义

 我们现在有一个集合 A A A和一个集合 E E E,分别为初始的点集合和初始的边集合,此外我们还有一个集合 B B B ,为记录我们选择的点的集合,集合 E a n s Eans Eans 是被选择边的集合,开始的时候任意从 A A A 中选择一个点加入到 B B B 中,随后查找距离 B B B 中点最近的点,将它加入到 B B B 中,将使用的边加入到集合 E a n s Eans Eans 中去。最终 E a n s Eans Eans 中的边就是我们的最小生成树的所有边。

2 代码实现

memset(minn,127,sizeof minn);
minn[1] = 0;
for(int i = 1;i <= n;i++)
{
    int k = 0;
    for(int j = 1;j <= n;j++) if(!vis[j]&&(minn[j] < minn[k])) k = j; // 得到距离集合点最近的点的位置
    ans += min[k]; // 这条边就是我们的选择
    vis[k] = true; // 标记已经被选择
    for(int j = 1;j <= n;j++)
       if(!vis[j]&&f[k][j])
       {
           minn[j] = min(minn[j],f[k][j]); // 基于这个点再进行更新一波,
       }
}

3 prime算法的优化

​ 在prime算法中,我们可以知道我们要去选择的是距离点集合 B B B 最近的那个点,对于这样一个问题,我们可以使用二叉堆进行优化,在小根堆中,最顶端的永远是最小的那个数,听大佬说再稠密图中使用堆优化的效果一般,emmm

二叉堆的实现 ,其实也可以直接使用 q u e u e . h queue.h queue.h中的 p r i o r i t y _ q u e u e priority\_queue priority_queue,就不用自己再去造轮子了

memset(dis,0x7f,sizeof(dis)); dis[1]=0;
cnt=0;
q.push(data{1,0});
while(!q.empty()&&cnt<n)
{
    int d=q.top().cost,u=q.top().to;
    q.pop();
    if(vis[u]) continue;
    ++cnt; ans+=d; vis[u]=1;
    for(int i=head[u];i;i=E[i].next)
       if(E[i].cost<dis[E[i].to])
           dis[E[i].to]=E[i].cost,q.push(data{E[i].to,E[i].cost});
}
if(cnt==n) printf("%d",ans);
else printf("-1");

二 Kruskal算法

1. 定义

kruskal算法核心其实就是并查集,不断合并块,直至最后只剩一个块,每次选择的是最短的边,如果两边不同就合并。

2 code

int k = 0;
sort(a+1,a+1+m);
for(int i = 1;i <= m;i++)
{
    if(find(a[i].x)!=find(a[i].y))
    {
        ans = a[i].value;
        join(a[i].x,a[i].y);
        k++;
        if(k==n-1) break;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值