首页 > 编程语言 >【图论】最小生成树与Prim、Kruskal算法

【图论】最小生成树与Prim、Kruskal算法

时间:2024-03-12 18:23:33浏览次数:18  
标签:tmp 图论 Prim lrlen Kruskal pos vector holder size

求图的最小生成树的Prim、Kruscal算法,其实都是由最小生成树的性质推来的,掌握了该性质,便能较容易地推导出这两种算法。

最小生成树的性质

无向图G的顶点集为 V V V,设 U U U为 V V V的真子集, u ∈ U u\in U u∈U, v ∈ ( V − U ) v\in (V- U) v∈(V−U),边u-v是连通 U U U、的所有边中权重最小的一条,则边u-v一定在G的最小生成树(MST)中。
反证法证明:假设T是一个MST,边u-v不在该MST中,先把它加入到T,则出现包含该边的环;T中必存在另一条边 u ′ − v ′ u^\prime-v^\prime u′−v′,连接题中两个集合,删除它后,环消失,出现新的MST,并且比原MST的权重更小,矛盾。

Prim算法

思路就是任取一个顶点作为初始U,不断寻找连接两个子集的所有边中权重最小的一条,把此边在 V − U V-U V−U上的顶点移到 U U U,重复这个操作,直至U包含全部顶点。

Kruscal算法

直接将所有边按权重排序,从小到大,每次尝试添加一条到MST,如果加入后没有产生环就加入该边,否则跳过。

松弛操作

两种算法都用了求最值问题的松弛操作思路,相似的例子,求K个已排序数组的最短公共区间,该区间包含每个数组至少一个元素,初始化选择各个数组首个元素组成集合的最小最大值,然后松弛,选择最小值所在数组向右取元素,更新区间。

#include <vector>
#include <utility>
#include <numeric>
#include <iostream>
#include <limits>
#include <tuple>
using namespace std;
class Solution {
public:
    vector<int> smallestRange(vector<vector<int> > &nums)
    {
        bool stop = false;
        int length = 2e5;
        int left = -1e5;
        int right = 1e5;
        vector<size_t> v_pos;
        vector<size_t> v_size;
        vector<int> holder;
        std::vector<int> lrlen{left, right, length};
        Init(nums, v_pos, v_size, holder);
        UpdateLeftRight(nums, v_pos, v_size, holder, lrlen, stop);
        while (!stop) {
            UpdateLeftRight(nums, v_pos, v_size, holder, lrlen, stop);
        }
        return {lrlen[0], lrlen[1]};
    }

    tuple<size_t, int, int> GetMinMax(const vector<int> &holder_)
    {
        int min = numeric_limits<int>::max();
        int max = numeric_limits<int>::min();
        size_t pos = 0;
        for (size_t i = 0; i < holder_.size(); i++) {
            if (min > holder_[i]) {
                min = holder_[i];
                pos = i;
            }
            if (max < holder_[i]) {
                max = holder_[i];
            }
        }
        return {pos, min, max};
    }
    void UpdateLeftRight(const vector<vector<int> > &nums, vector<size_t> &v_pos, vector<size_t> &v_size,
                         vector<int> &holder, std::vector<int> &lrlen, bool &stop)
    {
        auto res = GetMinMax(holder);
        int tmp_left = get<1>(res);
        int tmp_right = get<2>(res);
        size_t pos = get<0>(res);
        if (v_pos[pos] == (nums[pos].size() - 1)) {
            stop = true;
        }
        v_pos[pos]++;
        int tmp_length = tmp_right - tmp_left;
        if (tmp_length < lrlen[2] || (tmp_length == lrlen[2] && tmp_left < lrlen[0])) {
            lrlen[0] = tmp_left;
            lrlen[1] = tmp_right;
            lrlen[2] = tmp_length;
        }
        holder.clear();
        for (size_t i = 0; i < v_pos.size(); i++) {
            holder.push_back(nums[i][v_pos[i]]);
        }
    }
    void Init(const vector<vector<int> > &nums, vector<size_t> &v_pos, vector<size_t> &v_size, vector<int> &holder)
    {
        v_pos.clear();
        v_size.clear();
        holder.clear();
        for (size_t i = 0; i < nums.size(); i++) {
            v_pos.push_back(0);
            v_size.push_back(nums[i].size());
            holder.push_back(nums[i][0]);
        }
    }
};
int main()
{
    Solution A;
    vector<int> a{4, 10, 15, 24, 26};
    vector<int> b{0, 9, 12, 20};
    vector<int> c{5, 18, 22, 30};
    vector<vector<int> > q{a, b, c};
    auto res = A.smallestRange(q);
    for (auto i : res) {
        cout << i << " ";
    }
    cout << endl;
    a.clear();
    b.clear();
    c.clear();
    for (int i = 1; i < 4; i++) {
        a.push_back(i);
        b.push_back(i);
        c.push_back(i);
    }
    vector<vector<int> > qb{a, b, c};
    res = A.smallestRange(qb);
    for (auto i : res) {
        cout << i << " ";
    }
    return 0;
}

标签:tmp,图论,Prim,lrlen,Kruskal,pos,vector,holder,size
From: https://blog.csdn.net/CSUzhangpeike/article/details/136658197

相关文章

  • cmd 的图论练习题(近期总结 2024.3.11)
    AGC010ERearranginglink题意:一个序列\(a_{1...n}\),两个人游戏。先手打乱这个序列,然后后手可以多次选择一对相邻的互质的数交换。先手希望最终序列字典序尽量小,后手则相反。两人都绝顶聪明,求最终序列。\(1\len\le2000,\space1\lea_i\le10^8\)考虑不互质的两个数\(a_i,a......
  • UVA12101 Prime Path
    PrimePath\(link\)题面翻译给你个整数\(T(T\leq100)\),接下来\(T\)行数据。每次给你俩数\(a,b\)(保证都是四位数且都为无前导零的质数),问\(a\)经过几次变换可以变成\(b\)。输出最少可以经过几次变换变成\(b\)的次数。如果变不成直接输出Impossible。规定\(a\)可以......
  • P9632 [ICPC2020 Nanjing R] K Co-prime Permutation
    原题链接题解我一开始也很困惑,然后我想要不数据范围小一点我构造看看当\(n=5\)时\(k=0\)可不可以\(k=1\)可不可以\(k=2\)可不可以然后根据直觉,\(gcd(a,a+1)\)始终为一,且一和任何数的最大公约数都为一,自己和自己的最大公约数还是自己,所以萌生了以下想法把一后面......
  • 算法随笔——图论:无向图三/四元环计数
    参考:https://oi-wiki.org/graph/rings-count/题目链接:P1989无向图四元环计数求四元环步骤:建双向边。给每条边定向,由度数小的点指向大的,若度数一样则看编号大小。此时只有这几种情况:都可以归类为:枚举起始点A,枚举A<-->B(双向边),枚举B-->C,让C点被访问次数\(cnt\)......
  • dp&图论 杂题选做
    开个新坑qwq。upd:CSP前一周暂时停更。upd:暂时不会更了。P1099经典套路题。算法一:枚举。先dfs求出树的直径,再枚举直径上的每条路径,再dfs一遍求出最小偏心距即可。时间复杂度\(O(n^3)\),足以通过本题(由此可见本题有多水)。算法二:双指针。通过观察可以发现,在固定左端......
  • 【学习笔记】《综述图论中连通性及相关问题的一些处理方法》
    2023集训队论文第一篇。发现好像存在很多我不会/见过但是从来没记住过的结论之类的,所以这篇主要是背结论用的。目录无向图双连通性点双连通分量的性质耳分解割空间与环空间有向图可达性问题强连通性有向环竞赛图记\(u\rightsquigarrowv\)为\(u\)到\(v\)的路径,\(u\t......
  • c++ primer ch2笔记
    ch22.1基本内置类型C++基本内置类型void算术类型整形(包括字符,bool)浮点型最小尺寸:整形尺寸大小受编译器影响,但是至少会保证一个最小尺寸,int最小尺寸2字节相互关系:int至少和一个short一样大无符号类型:unsignedint、unsignedlong类型转换规则:布......
  • Pursuit For Artifacts 题解(图论)
    PursuitForArtifacts题解题目给定一张\(n\)个点\(m\)条边的简单无向连通图,边有边权,边权要么为\(0\),要么为\(1\)。每条边只能通过一次(两个方向加起来只能通过一次)。求是否存在一条从\(a\)到\(b\)的路径,满足路径上至少存在一条权为\(1\)的边。\(1\leqn,m\l......
  • 图论算法汇总
    图论算法在信息学竞赛中有着非常广泛的应用,也频繁在考试与比赛中作为重要的考察知识.本文汇总并分类了信息学竞赛中的图论算法.1生成树与最短路1.1Prim算法Prim算法可以求出一张图的最小生成树,时间复杂度为\(\mathcal{O}((|V|+|E|)\log|V|)\).memset(dis,0x3f,sizeo......
  • [ARC155D] Avoid Coprime Game 题解
    Description非负整数\(x,y\)的最大公约数记为\(\gcd(x,y)\),规定\(\gcd(x,0)=\gcd(0,x)=x\)。黑板上写了\(N\)个整数\(A_1,A_2,...,A_N\),这\(N\)个数的最大公约数是\(1\)。Takahashi和Aoki在玩游戏,有一个变量\(G\)初值为\(0\),他们轮流进行以下操作:从黑板上选择......