首页 > 其他分享 >并查集和最小生成树

并查集和最小生成树

时间:2023-01-08 20:44:55浏览次数:43  
标签:const int fy 查集 最小 生成 集合

并查集

初始化\(O(n)\)

int fa[N], szp[N], sze[N], loop[N]; //fa根节点,szp点的数量,sze边的数量,loop自环的数量
int n, m;                           //n代表点数,m代表边数
void init()                         //初始化
{
    for (int i = 1; i <= n; ++i)
        fa[i] = i, szp[i] = 1, sze[i] = 0, loop[i] = 0;
}

查找:已实现路径压缩\(O(\alpha (n))\)

int find(int x)
{
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}

合并\(O(\alpha (n))\)

void merge(int x, int y)
{
    int fx = find(x);
    int fy = find(y);
    sze[fy]++;
    if (fx != fy)
    {
        fa[fx] = fy;
        sze[fy] += sze[fx];
        szp[fy] += szp[fx];
        loop[fy] += loop[fx];
    }
}

最小生成树(minimum spanning tree)

基础知识

图是一个二元组\(G(V(G),E(G)),V(G)\)代表点的集合,E(G)代表边的集合

对于V中的每个元素,我们可以称他为顶点或者节点

一个没有固定根结点的树称为 无根树(unrooted tree)。无根树有几种等价的形式化定义:

1.有n个结点,n-1条边 的连通无向图

2.无向无环的连通图

3.任意两个结点之间有且仅有一条简单路径的无向图

4.任何边均为桥的连通图

5.没有圈,且在任意不同两点间添加一条边之后所得图含唯一的一个圈的图

在无根树的基础上,指定一个结点称为 ,则形成一棵 有根树(rooted tree)。

生成树:一个连通无向图的生成子图,同时要求是树。也即在图的边集中选择n-1条,将所有顶点连通。

那么 最小生成树 就是边权和最小的生成树

注意:只有连通图才有生成树,而对于非连通图,只存在生成森林。

Kruskal算法:适合点多边少的稀疏图\(O(mlogm)\)

基本思想

本质为贪心算法,从边角度考虑问题,我们按照边权由小到大排序,然后我们进行加边。

怎么加边呢?我们首先利用并查集查找两个点是否在同一个集合中(也称一颗树),如果不在,那么他们一定属于两个不同的集合(相当于两个森林),然后我们使用并查集合并即可;如果两个点在同一集合中,我们就不需要操作了

array<int, 3> edge[N*100];
int num, ans;
void Kruskal()
{
    sort(edge+1,edge+m+1);
    num = 0,ans=0;
    for (int i=1;i<=m;++i)
    {
        auto [w,u,v] = edge[i];
        if (find(u)!=find(v))
        {
            ans+=w;
            num++;
            merge(u,v);
        }
    }
}
int main(void)
{
    Zeoy;
    int t = 1;
    // cin >> t;
    while (t--)
    {
        cin >> n >> m;
        for (int i = 1, u, v, w; i <= m; ++i)
        {
            cin >> u >> v >> w;
            edge[i] = {w, u, v};
        }
    }
    return 0;
}

Prim算法:适合点少边多的稠密图\(O(n^2+m)\)

基本思想

点角度考虑问题,利用邻接矩阵记录节点之间的权值,任选一个节点开始,然后找一个没有在集合中并且距离集合最近的(也就是到集合的权值最小)点加入集合,然后利用这个点去更新其他不在集合里的点到集合的距离,实际上把所有点分为两个集合,一个是已经加入最小生成树的集合,另一个是还未加入最小生成树的集合,重复以上步骤直到最小生成树集合中存在n-1条边

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e5 + 10;
int n, m;                   // n代表点数,m代表边数
int num, ans;
const int inf = 0x3f3f3f3f;         
int dis[N], vis[N];         //dis表示到最小生成树集合的最短距离,vis代表这个节点在不在最小生成树集合中
int g[N][N];                //邻接矩阵存图
void Prim()
{
    for (int i = 1; i <= n; ++i)
    {
        dis[i] = inf;       //初始化距离为inf
        vis[i] = 0;
    }
    dis[1] = 0;             //选第一个点加入集合
    for (int i = 1; i <= n; ++i)
    {
        int x = 0;
        for (int j = 1; j <= n; ++j)
        {
            if (!vis[j] && (x == 0 || dis[j] < dis[x]))     //找到距离集合距离最小的点
                x = j;
        }
        vis[x] = 1;
        for (int j = 1; j <= n; ++j)                        //更新其他未在集合中的点到集合的距离
        {
            if (!vis[i])
            {
                dis[i] = min(dis[i], g[x][j]);
            }
        }
    }
}
int main(void)
{
    Zeoy;
    int t = 1;
    // cin >> t;
    while (t--)
    {
        cin >> n >> m;
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= n; ++j)
            {
                g[i][j] = inf;
                g[i][i] = 0;
            }
        }
        for (int i = 1, u, v, w; i <= m; ++i)
        {
            cin >> u >> v >> w;
            g[u][v] = g[v][u] = min(g[u][v], w);
        }
        ans = 0;
        for (int i = 1; i <= n; ++i)
        {
            if (dis[i] == inf)      //生成不了生成树
                break;
            else
                ans += dis[i];
        }
        cout << ans << endl;
    }
    return 0;
}

标签:const,int,fy,查集,最小,生成,集合
From: https://www.cnblogs.com/Zeoy-kkk/p/17035302.html

相关文章

  • 【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的位置计算出来左右两边的长度,可以省略一些,这......
  • 输出指定学生成绩(15分)的样例三的问题
    输出指定学生成绩(15分)题目内容:   从键盘输入3个同学4门课的成绩,输出指定同学的成绩和平均分。输入格式:   输入3个同学4门课的成绩输出格式:   输出指定......
  • 基于MFC的学生成绩管理系统
    1.基本功能演示​1.1软件登陆界面​为实现多账户的登陆方式,故采用了标签页组合的方式,每个分页面指向一个登录窗口。​1.2学生界面​学生界面所需要的功能为课程分数查询,功能......
  • fastposter v2.11.0 天花板级的海报生成器
    fastposterv2.11.0天花板级的海报生成器......