最小生成树模板总结(Prim、Kruskal)

Prim:

贪心准则:加入后仍形成树,且耗费最小

算法过程:从单一顶点的树T开始,不断加入耗费最小的边(u,v),使T∪{(u,v)}仍为树(u,v中有一个已经在T中,另一个不在T中)

void prim()
{
    priority_queue<PII,vector<PII>,greater<PII>>q;//小根堆维护最小边值
    vis[1]=1;//初始任意加一个点到T中
    for(int i=head[1];i;i=ed[i].next)//与之相邻的边加入队列
    {
        int x=ed[i].x,w=ed[i].w;
        q.push({w,x});
    }
    while(q.size())
    {
        auto p=q.top();
        q.pop();
        int x=p.second,w=p.first;
        if(vis[x])continue;//如果当前最小边连接的点已在树T中,continue
        ans+=w;//否则最小生成树值加上当前边权值
        vis[x]=1;//标记,即把这个点加入到数T中
        for(int i=head[x];i;i=ed[i].next)//与之相连的边放入队列
        {
        int x=ed[i].x,w=ed[i].w;
        q.push({w,x});
        }
    }
}

小优化:在添加边到队列中时,如果添加的边并没有减少连接的点到树的距离时,可以不用添加到队列中。

int dis[100010];//表示每个点到树的距离
void prim()
{
    priority_queue<PII,vector<PII>,greater<PII>>q;
    memset(dis,0x7f,sizeof(dis));
    vis[1]=1;
    for(int i=head[1];i;i=ed[i].next)
    {
        int x=ed[i].x,w=ed[i].w;
        if(w<dis[x]){
             q.push({w,x});
             dis[x]=w;
         }
   }
    while(q.size())
    {
        auto p=q.top();
        q.pop();
        int x=p.second,w=p.first;
        if(vis[x])continue;
        ans+=w;
        vis[x]=1;
        for(int i=head[x];i;i=ed[i].next)
        {
        int x=ed[i].x,w=ed[i].w;
        if(w<dis[x]){
             q.push({w,x});
             dis[x]=w;
         }
        }
    }
}

//代码类似dij,dij为到源点的最小值,此为到树的最小值

复杂度:(n+m)logm

Kruskal算法:

思想:贪心选取最短的边来组成一颗最小的生成树

做法:先将所有的边排序,然后利用并查集作判断(这条边连接的两个点属于两个集合)来优先选择最小的边,直到建成一颗生成树。

struct no
{
    int x,y,z;
    bool operator<(const no &a)const {
       return z<a.z;
    }
}ed[200010];
int find(int x)
{
    return x==fa[x]?x:fa[x]=find(fa[x]);
}


for(int i=1;i<=m;i++)
    {
        cin>>ed[i].x>>ed[i].y>>ed[i].z;
    }
    sort(ed+1,ed+1+m);
    for(int i=1;i<=m;i++)
    {
        int fx=find(ed[i].x);
        int fy=find(ed[i].y);
        if(fx==fy)continue;
        ans+=ed[i].z;
        fa[fx]=fy;
    }

小优化:可以用一个变量cnt记录已经加入边的数量,cnt==n-1时结束循环。

复杂度:m*logm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nj745

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值