*最小生成树-prim算法(Dijstra)

# 2023大厂真题提交网址(含题解):
www.CodeFun2000.com(http://101.43.147.120/)

最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
![在这里插入图片描述](https://img-blog.csdnimg.cn/b10d8a3a07e44918b4510841db778849.png)

核心思想:
分阶段,一步一步贪心的求最小值.

算法过程:(贪心,动态规划)
将图中点分成两个集合,一个是在最小生成树中,一个尚不在。称为P,Q集合(用book数组标记)
dis[i]代表某个阶段第i个点到最小生成树的最近的距离(实质是边的权值).最开始都为INF.
最开始P集合为空,Q为全集
最终态P为全集,Q集合为空
1.将任意一个点放入优先队列W.对应dis值置0.
2.当W不为空时,从里面拿出一个离最小生成树最近的一个边.(最开始为0)
3.对这个边的终点E进行拓展,将所有能够更新dis数组的边推入W(边的终点S要在Q集合中).
4.跳到2.

解释:
复杂度:O(MlogM) ----M为边数
①过程大致是从邻接着现阶段最小生成树的所有边里选取最短的一个边去拓展这颗树.
②走完之后得到的dis数组就是最小生成树的边.(如果想输出路径,另开数组保存信息就好)
③Djistra求单源最短路把dis数组的含义从 从i到最小生成树集合最小距离改成i到起点s的最小距离就好.

Dijstra求最短路模板:
https://www.luogu.com.cn/record/31353188

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxe = 4e5+5; //无向边记得开两倍大!
const int maxv = 5e3+5;
const int INF = 0x3f;
int u[maxe],v[maxe],w[maxe],first[maxv],nextt[maxe];
int sign,n,m,vis[maxv];
struct Node
{
    int num,dis;
    Node(int n = 0,int d = 0)
    {
        num = n,dis = d;
    }
    bool operator < (const Node & a) const
    {
        return dis > a.dis; //dis小的排前面
    }
}node[maxe];
void addedge(int x,int y,int z)
{
    u[++sign] = x;
    v[sign] = y;
    w[sign] = z;
    nextt[sign] = first[x];
    first[x] = sign;
}
priority_queue<Node>Q;
int prim(int s)
{
    int ans = 0;
    int dis[maxv];
    memset(dis,INF,sizeof dis);
    dis[s] = 0;
    Node temp(s,0);
    Q.push(temp); //把起点推入队列
    while(!Q.empty())
    {
        temp = Q.top();
        Q.pop();
        int g = temp.num;
        if(vis[g]) continue; //已经在P集合的节点不再更新
        vis[g] = 1;
        for(int i = first[g];i;i = nextt[i])
        {
            if(dis[v[i]] > w[i] && !vis[v[i]])
            {
                dis[v[i]] = w[i];
                Q.push(Node(v[i],dis[v[i]]));
            }
        }
    }
    for(int i = 1;i<=n;i++)
        if(!vis[i])
            return -1;
        else
            ans += dis[i];
    return ans;
}
int main()
{

    scanf("%d%d",&n,&m);
    int x,y,z;
    for(int i = 1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        addedge(x,y,z);
        addedge(y,x,z);
    }
    int ans = prim(x);
    if(ans == - 1)
        printf("orz\n");
    else
        printf("%d\n",ans);
    return 0;
}


//

/*


4 3
1 2 7
1 3 4
2 3 1

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值