首页 > 其他分享 >通关搜索和图论 day_16 -- Prim & Kruskal

通关搜索和图论 day_16 -- Prim & Kruskal

时间:2023-01-13 11:36:15浏览次数:54  
标签:Prim 16 -- 最小 距离 生成 int 集合 dist

Prim

先初始化距离,全部是正无穷,然后 n 次迭代,每次迭代执行:

1.找到 不在集合当中的 距离最小的点(这里的集合是 当前的生成树

2.用这个点更新其他点到集合的距离

举例,我们有如下图

image-20230111092121285

第一步,让所有点到集合的距离变 +无穷

然后因为所有点的距离都是正无穷,所以我们随便挑一个点作为第一个点,把他加入集合

其他点到集合的距离,实际就是看看其他点能不能连一条线到集合内部

那么某个点到集合的距离就定义成,这个点到集合任意一条边最小的距离,如果这个点没有一条边连到集合,那么距离就被定义成正无穷

那么现在 2号点到集合的距离被更新成1

3号点到集合的距离被更新成2

4号点到集合的距离被更新成3

第二次迭代就找集合外 距离最近的点也就是 2 号点

重复上述过程,直到所有点进入集合

生成树是什么呢?就是每次选择的那个点指向集合的边就是我们生成树的一条边

模板

int n;      // n表示点数
int g[N][N];        // 邻接矩阵,存储所有边
int dist[N];        // 存储其他点到当前最小生成树的距离
bool st[N];     // 存储每个点是否已经在生成树中


// 如果图不连通,则返回INF(值是0x3f3f3f3f), 否则返回最小生成树的树边权重之和
int prim()
{
    memset(dist, 0x3f, sizeof dist);

    int res = 0;
    for (int i = 0; i < n; i ++ )
    {
        int t = -1;
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;

        if (i && dist[t] == INF) return INF;

        if (i) res += dist[t];
        st[t] = true;

        for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);
    }

    return res;
}

例题

858. Prim算法求最小生成树 - AcWing题库

给定一个 n 个点 m 条边的无向图,图中可能存在重边和自环,边权可能为负数。

求最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

给定一张边带权的无向图 G=(V,E),其中 V 表示图中点的集合,E 表示图中边的集合,n=|V|,m=|E|。

由 V 中的全部 n 个顶点和 E 中 n−1 条边构成的无向连通子图被称为 G 的一棵生成树,其中边的权值之和最小的生成树被称为无向图 G 的最小生成树。

输入格式

第一行包含两个整数 n 和 m。

接下来 m 行,每行包含三个整数 u,v,w,表示点 u 和点 v 之间存在一条权值为 w 的边。

输出格式

共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

数据范围

1≤n≤500,
1≤m≤105,
图中涉及边的边权的绝对值均不超过 10000。

输入样例:

4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4

输出样例:

6
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;

const int N = 510,INF = 0x3f3f3f3f;
int n,m;
int g[N][N];
int dist[N];
bool st[N];

int prim()
{
    //  把所有距离初始化成正无穷
    memset(dist,0x3f,sizeof dist);
    int res = 0;    //res 存的是最小生成树里所有边的长度之和
    //  n 次迭代
    for (int i = 0; i < n; i++) {
        int t = -1;
        for (int j = 1; j <= n ; j++) {
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
            {
                t = j;
            }
        }

        if (i && dist[t] == INF) return INF;    // 不是第一个点,到集合的距离还是正无穷说明无法生成最小生成树
        if (i) res += dist[t];
        for (int j = 1; j <= n ; j++) {
            dist[j] = min(dist[j],g[t][j]);
        }

        st[t] = true;
    }
    return res;
}

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    cin >> n >> m;
    memset(g,0x3f,sizeof g);
    while(m--)
    {
        int a,b,c;
        cin >> a >> b >> c;
        g[a][b] = g[b][a] = min(g[a][b],c);
    }

    int t = prim();
    if (t == INF) cout << "impossible" << endl;
    else cout << t << endl;
}

Kruskal

第一步 先将所有边 按照权重从小到大排序

第二步 枚举每条边 ab 权重为 c

如果 ab 不连通,将这条边加入集合中

模板

int n, m;       // n是点数,m是边数
int p[N];       // 并查集的父节点数组

struct Edge     // 存储边
{
    int a, b, w;

    bool operator< (const Edge &W)const
    {
        return w < W.w;
    }
}edges[M];

int find(int x)     // 并查集核心操作
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int kruskal()
{
    sort(edges, edges + m);

    for (int i = 1; i <= n; i ++ ) p[i] = i;    // 初始化并查集

    int res = 0, cnt = 0;
    for (int i = 0; i < m; i ++ )
    {
        int a = edges[i].a, b = edges[i].b, w = edges[i].w;

        a = find(a), b = find(b);
        if (a != b)     // 如果两个连通块不连通,则将这两个连通块合并
        {
            p[a] = b;
            res += w;
            cnt ++ ;
        }
    }

    if (cnt < n - 1) return INF;
    return res;
}

例题

859. Kruskal算法求最小生成树 - AcWing题库

给定一个 n 个点 m 条边的无向图,图中可能存在重边和自环,边权可能为负数。

求最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

给定一张边带权的无向图 G=(V,E),其中 V 表示图中点的集合,E 表示图中边的集合,n=|V|,m=|E|。

由 V 中的全部 n 个顶点和 E 中 n−1 条边构成的无向连通子图被称为 G 的一棵生成树,其中边的权值之和最小的生成树被称为无向图 G 的最小生成树。

输入格式

第一行包含两个整数 n 和 m。

接下来 m 行,每行包含三个整数 u,v,w,表示点 u 和点 v 之间存在一条权值为 w 的边。

输出格式

共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

数据范围

1≤n≤105,
1≤m≤2∗105,
图中涉及边的边权的绝对值均不超过 1000。

输入样例:

4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4

输出样例:

6
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;

const int N = 2000010;
int n,m;
int p[N];

struct Edge{
    int a,b,w;

    bool operator< (const Edge &W)const{
        return w < W.w;
    }
}edges[N];

int find(int x)
{
    if (p[x] != x)
    {
        p[x] = find(p[x]);
    }
    return p[x];
}


int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    cin >> n >> m;

    for (int i = 0; i < m; ++i) {
        int a,b,w;
        cin >> a >> b >> w;
        edges[i] = {a,b,w};
    }

    sort(edges,edges + m);

    // 初始化并查集
    for (int i = 1; i <= n; i ++ ) p[i] = i; 

    // 从小到大枚举所有边
    int res = 0, cnt = 0;
    for (int i = 0; i < m; i ++ )
    {
        int a = edges[i].a, b = edges[i].b, w = edges[i].w;

        a = find(a), b = find(b);
        if (a != b)
        {
            p[a] = b;
            res += w;
            cnt ++ ;
        }
    }
    
    if (cnt < n - 1)
    {
        cout << "impossible" << endl;
    }else{
        cout << res << endl;
    }
}

标签:Prim,16,--,最小,距离,生成,int,集合,dist
From: https://www.cnblogs.com/ShibuyaKanon/p/17049075.html

相关文章

  • Ubuntu20.04通过realmd+sssd实现AD账号登陆
    Ubuntu20.04通过realmd+sssd实现AD账号登陆:apt-getinstallrealmdsssdsssd-toolsrealmdiscover​​aa.ming.com​​(aa.ming.com为DC)sssd模式(会自动安装sssd、sssd-......
  • 用SGDK开发世嘉MD游戏:调试篇
    用SGDK开发世嘉MD游戏:调试篇本来想直接讲MD游戏开发的部分,但我还是觉得有必要先把调试这部分讲一下由于世嘉MD属于上古时代的游戏主机,那时候的开发环境非常非常的......
  • 通关搜索和图论 day_17 -- 染色法 & 匈牙利算法
    染色法一个图是二分图当且仅当她可以被2染色(不含有奇数环)流程如下,先找到一个不在集合中的点把他放在左边然后遍历这个点有连接的点,把这些点放到右边,再依次遍历放到右......
  • Thanos 配置Prometheus的高可用 (一)
    标签(空格分隔):Prometheus系列一:Prometheus的介绍与架构1.1Prometheus的概述1.prometheus的介绍Prometheus是一个开源的系统监控和告警工具包,最初由SoundCloud开......
  • (六)elasticsearch 源码之选主流程分析
    1.概述es(elasticsearch,下同)的选举流程相对来说比较简单,使用的bully算法,简而言之,就是谁强谁就是老大,待会儿看下怎么判定谁更强。2.选主流程在启动篇中我们讲解了节点启动......
  • 新一代云原生日志架构 - Loggie的设计与实践
    Loggie萌芽于网易严选业务的实际需求,成长于严选与数帆的长期共建,持续发展于网易数帆与网易传媒、中国工商银行的紧密协作。广泛的生态,使得项目能够基于业务需求不断完善、......
  • shiro登录认证过程讲解
    先粘出登录的代码​@RequestMapping(value="/submitLogin",method=RequestMethod.POST)@ResponseBodypublicMap<String,Object>submitLogin(Stringusername,String......
  • MySQL必知必会第七章-数据过滤
    数据过滤组合WHERE子句操作符(operator)用来联结或改变WHERE子句中的子句的关键字。也称为逻辑操作符(logicaloperator)。AND操作符为了通过不止一个列进行过滤,可使用AND......
  • java中关于继承,多态及方法调用的底层细节
    java中关于继承,多态及方法调用的底层细节一、继承继承已存在的类就是复用(继承)这些类的方法和域。在此基础上,还可以添加一些新的方法和域,以满足新的需求。子类会拥有......
  • 河北稳控科技振弦采集模块的各种参数操作
    河北稳控科技振弦采集模块的各种参数操作固件版本读取点击指令区【读取版本】按钮,读取当前连接模块的固件版本信息,读取到的版本信息显示于按钮右侧。VMTool会根据读取......