首页 > 其他分享 >最小生成树

最小生成树

时间:2023-01-09 00:44:28浏览次数:45  
标签:cur weight int 最小 生成 顶点 edg

最小生成树定义:

构造连通网的最小代价生成树称为最小生成树(Minimum Cost Spanning Tree)。即有n个城市,如何修最短的路将所有的城市连接起来。

构造最小生成树主要有两种算法一种是普里姆(Prim)算法,一种是克鲁斯卡尔(Kruskal)算法。

Prim在稠密图中比Kruskal优,在稀疏图中比Kruskal劣。Prim是以更新过的节点的连边找最小值,Kruskal是直接将边排序。

         1.普里姆算法

先选择图中任意一个顶点作为起始点,之后选择连接这个顶点最短的一条边,将其与另一个顶点连接上。将这两个已经连接的点看成一个入度更多的一个大顶点,继承两个

顶点的所有边,之后再找出这个大顶点最短的一条边,将其与另一个顶点连接上。以此类推将这已经连接的三个点继续看成一个大顶点,继续连接,直到图中所有的顶点已经

连接上,这样构成的图便是一个最小生成树。

普里姆算法主要基于一个判断:对于任意一个顶点v,连接到该顶点的所有边中的一条最短边(v, vj)必然属于最小生成树。

int n, m;
int dis[5005], vis[5005];//dis记录当前到所有点的最小值,vis判断当前点是否走过
struct edge {
    int to, weight;//储存边的结构体,to终点,weight权值
};
vector<edge>edg[5005];//储存边的邻接表
class Solution {
public:
    static int prim() {
        int tot = 0, cur = 0, answer = 0;//tot已经连接的点的数量,cur当前连接的点,answer答案
        for (int i = 1; i <= n; i++) {
            vis[i] = 0; dis[i] = 0x7fffffff;//初始化数组
        }
        dis[1] = 0;//选择1号顶点为初始点
        while (++tot <= n) {
            int minn = 0x7fffffff;
            for (int i = 1; i <= n; i++) {//寻找最短边
                if (!vis[i] && dis[i] < minn) {
                    minn = dis[i];
                    cur = i;
                }
            }
            answer += dis[cur];//更新答案
            vis[cur] = 1;//标记当前点已经走过
            for (int i = 0; i < edg[cur].size(); i++) {//用当前选出的点更新距离数组dis
                dis[edg[cur][i].to] = min(dis[edg[cur][i].to], edg[cur][i].weight);
            }
        }
        return answer;
    }
};

       2.克鲁斯卡尔算法

克鲁斯卡尔算法相比普里姆算法更好理解,第一步将图中所有的边放到一个数组里面,第二部将数组中的边按照权值从小到大排序 ,第三部从小到大选择n-1条边加入生成树中,同时利用

并查集来保证不会形成环。这样构成的生成树就是最小生成树。

bool cmp(edge x, edge y) {
    return x.weight < y.weight;
}
class Solution
{
    static int find_father(int x) {
        return fa[x] == x ? x : fa[x] = find_father(fa[x]);//寻找父节点
    }
public:
    static void Kruskal() {
        int n, m, ans = 0, tot = 0;
        cin >> n >> m;
        for (int i = 1; i <= n; i++)fa[i] = i;
        for (int i = 1; i <= m; i++) {
            int at, to, w;
            cin >> at >> to >> w;
            edge cur;
            cur.at = at; cur.to = to; cur.weight = w;
            edg.push_back(cur);
            cur.at = to; cur.to = at;
            edg.push_back(cur);//储存双边
        }
        sort(edg.begin(), edg.end(), cmp);
        for (int i = 0; i < edg.size(); i++) {
            int at = edg[i].at, to = edg[i].to;
            if (find_father(at) != find_father(to)) {
                fa[find_father(at)] = fa[to];
                ans += edg[i].weight;
                tot++;
            }
            if (tot == n - 1)break;//取了n-1个边便可以停止
        }
        if (tot < n - 1)cout << "orz";
        else cout << ans;
    }
};

 

标签:cur,weight,int,最小,生成,顶点,edg
From: https://www.cnblogs.com/redintoncforever/p/17035836.html

相关文章

  • Python 中的生成器实现原理
    1.如何生成一个巨大的序列1.1需求描述要求生成一个包含很多元素的序列,假设:存储1个整数需要4个字节现在要创建一个包含1G个整数的序列,从0到1*1024*1024*......
  • 基于matlab的最小支配集CDS仿真
    1.算法描述       支配集的定义如下:给定无向图G=(V,E),其中V是点集,E是边集,称V的一个子集S称为支配集当且仅当对于V-S中任何一个点v,都有S中的某个点u,使得(u,......
  • 并查集和最小生成树
    并查集初始化\(O(n)\)intfa[N],szp[N],sze[N],loop[N];//fa根节点,szp点的数量,sze边的数量,loop自环的数量intn,m;//n代表点数,m代表边......
  • 【LeetCode数组#4】长度最小的子数组
    长度最小的子数组力扣题目链接(opensnewwindow)给定一个含有n个正整数的数组和一个正整数s,找出该数组中满足其和≥s的长度最小的连续子数组,并返回其长度。如......
  • 建设APP 一切为了在大学生成长
        高校要抓紧以手机APP为载体,学生成长体系为模型,聚合校内及校外互联网优质的内容和应用,为大学生提供学习、生活、就业等全面优质服务的移动互联网平台。   ......
  • 海豚号码的生成器
    海豚号码的生成器,你可以在电脑上打开下面的网www.haitunrj.com进去。它是在电脑上用的。它具有多种号码生成功能、号码导入通讯录和对号码进行综合整理的功能。具体说有这七......
  • 【230108-1】若x,y都是正实数,并且x+y=2015,则y/x+x/y的最小值是()
    ......
  • 美团开放平台SDK自动生成技术与实践
    美团开放平台为整个美团提供了20+业务场景的开放API,为了使开发者能够快速且安全的接入美团开放平台,美团开放平台提供了多种语言的SDK来提高开发者的接入效率。本文介绍了美......
  • LLVM IR 代码生成与解析器、抽象语法树
    LLVMIR代码生成与解析器、抽象语法树概述将基于词法分析器,为Kaleidoscope构建一个完整的解析器(Parser)。通过解析器,我们可以定义并构造抽象语法树(AbstractSyntaxTre......
  • leetcode-1658. 将 x 减到 0 的最小操作数
    正向双指针有点麻烦,但是能通过,先提交一下,待我学习一下其他的解法再来提交这个里面不用对opNum进行计数,可以利用left和right的位置计算出来左右两边的长度,可以省略一些,这......