搜索与图论(三)——最小生成树、二分图

本文介绍了图论中的最小生成树算法,包括Prim算法和Kruskal算法,并讲解了如何在稠密图和稀疏图中选择合适的算法。此外,文章还探讨了二分图的染色法判别和匈牙利算法在求解二分图最大匹配中的应用。强调理解算法思路的重要性,建议通过实践来提高算法的熟练度。
摘要由CSDN通过智能技术生成

前言

算法基础课-3.4
第三章 搜索与图论(三)

共4题,知识点如下:
最小生成树:
Prim算法求最小生成树、
Kruskal算法求最小生成树。
二分图:
染色法判定二分图、
匈牙利算法—二分图的最大匹配。

掌握模版的最核心部分是:记住算法思路

不能纯记模版,效率很低,一定要记思路

可以想到啥算法,就自己把算法流程描述一遍

最小生成树

稠密图一般用朴素版Prim(主要是代码较短)

稀疏图一般用Kruskal算法(思路更简单而且代码也比堆优化版Prim少)

堆优化版Prim一般不会用到(也是适用于稀疏图)

在这里插入图片描述

堆优化版Prim和堆优化版Dijkstra,优化方式是一样的

所以略过,只讲朴素版Prim 和 Kruskal(实用主义,用到再学,用不到就暂时不学)

朴素版prim算法

朴素版Prim算法和Dijkstra非常相似

Dijkstra

先初始化,迭代n次,每次都找距离最近的点t(不在集合中的),然后用它更新其他点,再把它放到集合里去。
集合:(已经确定最短距离的点)

在这里插入图片描述

Prim

集合s:在当前连通块里的所有点

在这里插入图片描述
区别:

Dijkstra 是用 t 更新到起点的距离
Prim 是用 t 更新到集合的距离
t:不在集合中的距离最近的点

模板

时间复杂度是 O(n2+m), n 表示点数,m 表示边数

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;
}

模板题 AcWing 858. Prim算法求最小生成树

初始
在这里插入图片描述
随便挑一个更新到其他点的距离,然后将该点加入集合
在这里插入图片描述在这里插入图片描述
2(离集合最近的点)更新其他所有点,距离没有更短,没变化,加入到集合中
在这里插入图片描述
然后用3更新,最后用4,距离都没有变短,保持不变
在这里插入图片描述
最小生成树,最短的几条边(相等的任选一条即可)
在这里插入图片描述

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

using namespace std;
// 点500,边10w,稠密图,用邻接矩阵存
const int N = 510, INF = 0x3f3f3f3f;

int n, m;
int g[N][N];
int dist[N]; // 点到集合的距离
bool st[N];

int prim() {
   
    // 1.初始化
    memset(dist, 0x3f, sizeof dist);
    // 2.n次迭代
    int res = 0; // 存最小生成树的树边权重之和
    for (int i = 0; i < n; i++) {
   
        // 1) 每次找到集合外的所有点中距离最小的点
        int t = -1;
        for (int j = 1; j <= n; j++) {
   
            // !st[j]:集合外,t == -1:还没找到任何点, dist[t] > dist[j] : t的距离比j大
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        }
        
        // i!=0&&dist[t] == INF 当前距离最近的点到集合距离都是+∞,说明图是不连通的
        if (i && dist[t] == INF) return INF;
        // 只要不是第一个点,就把答案加上
        if (i) res += dist[t]; // 需要先累加再更新,防止把自环的加进去了
        
        // 2)用t更新其他点到集合的记录
        for (int j 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值