首页 > 其他分享 >第三章 图论与搜索三

第三章 图论与搜索三

时间:2023-02-12 23:44:32浏览次数:42  
标签:二分 图论 第三章 int Prim 算法 搜索 集合 匹配

最小生成树

最小生成树:由n个节点,和n-1条边构成的无向连通图被称为G的一颗生成树,在G的所有生成树中,边的权值之和最小的生成树,被称为G的最小生成树。(换句话说就是用最小的代价把n个点都连起来)

有两种常用算法:

  • Prim算法(普利姆)朴素版Prim(时间复杂度O(n2),适用于稠密图)堆优化版Prim(时间复杂度O(mlogn),适用于稀疏图)
  • Kruskal算法(克鲁斯卡尔)适用于稀疏图,时间复杂度O(mlogm)对于最小生成树问题,如果是稠密图,通常选用朴素版Prim算法,因为其思路比较简洁,代码比较短,如果是稀疏图,通常选用Kruskal算法,因为其思路比Prim简单清晰。堆优化版的Prim通常不怎么用。

朴素Prim

算法流程

  1. 初始化距离, 将所有点的距离初始化为INF

    (这里的距离指的是点到集合的距离,而Dijkstra的距离是到起点的距离)

  2. n次循环

    1. 找到不在集合s中, 且距离最近的点t

    2. 用t来更新其他点到的距离

      集合s

    3. 将t加入到集合s中

代码模板

// 时间复杂度是  O(n2+m)O(n2+m) , nn 表示点数,mm 表示边数
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;
}

Kruskal

算法流程

  1. 先将所有边,按照权重,从小到大排序
  2. 从小到大枚举每条边(a,b,w),若a,b不连通,则将这条边,加入集合中(将a点和b点连接起来)

代码模板

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


二分图

二分图

指的是,可以将一个图中的所有点,分成左右两部分,使得图中的所有边,都是从左边集合中的点,连到右边集合中的点。而左右两个集合内部都没有边。

Image

有两种常用的相关算法

  • 染色法
  • 匈牙利算法

其中染色法是通过深度优先遍历实现,时间复杂度是O(n×m);匈牙利算法的时间复杂度理论上是O(n×m),但实际运行时间一般远小于O(n×m)。

Image

图论中的一个重要性质:一个图是二分图,当且仅当图中不含奇数环奇数环,指的是这个环中边的个数是奇数。(环中边的个数和点的个数是相同的)

染色法

可以用染色法来判断一个图是否是二分图,使用深度优先遍历,从根节点开始把图中的每个节点都染色,保证每个节点与相邻节点的颜色不同(但是只有黑白两种),只要染色过程中没有出现矛盾,说明该图是一个二分图,否则,说明不是二分图。

匈牙利算法

解决的问题

匈牙利算法,是给定一个二分图,用来求二分图的最大匹配的。

二分图的匹配:给定一个二分图 G,在 G 的一个子图 M 中,M 的边集 {E} 中的任意两条边都不依附于同一个顶点,则称 M 是一个匹配。

二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。

代码模板

int n1, n2;     // n1表示第一个集合中的点数,n2表示第二个集合中的点数
int h[N], e[M], ne[M], idx;     // 邻接表存储所有边,匈牙利算法中只会用到从第一个集合指向第二个集合的边,所以这里只用存一个方向的边
int match[N];       // 存储第二个集合中的每个点当前匹配的第一个集合中的点是哪个
bool st[N];     // 表示第二个集合中的每个点是否已经被遍历过

bool find(int x)
{
    for (int i = h[x]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!st[j])
        {
            st[j] = true;
            if (match[j] == 0 || find(match[j]))
            {
                match[j] = x;
                return true;
            }
        }
    }

    return false;
}

// 求最大匹配数,依次枚举第一个集合中的每个点能否匹配第二个集合中的点
int res = 0;
for (int i = 1; i <= n1; i ++ )
{
    memset(st, false, sizeof st);
    if (find(i)) res ++ ;
}

标签:二分,图论,第三章,int,Prim,算法,搜索,集合,匹配
From: https://www.cnblogs.com/chenjq12/p/17115027.html

相关文章

  • 基于Astar算法的栅格地图目标最短路径搜索算法MATLAB仿真,带GUI界面
    1.算法描述Astar算法是一种图形搜索算法,常用于寻路。它是个以广度优先搜索为基础,集Dijkstra算法与最佳优先(bestfit)算法特点于一身的一种算法。它通过下面这个函数来......
  • 基于GA算法的TSP最短路径搜索matlab仿真
    1.算法描述(1)编码:将问题的候选解用染色体表示,实现解空间向编码空间的映射过程。遗传算法不直接处理解空间的决策变量,而是将其转换成由基因按一定结构组成的染色体。编码方式......
  • 第三章 图论与搜索二
    最短路问题常见的最短路问题可以分成两大类单源最短路多源汇最短路在最短路问题中,源点 也就是 起点,汇点 也就是 终点单源最短路单源最短路,指的是求一个点,到其......
  • 第三章 图论与搜索一
    普通DFS与BFS概述DFS:深度优先搜索(Depth-First-Search)BFS:宽度优先搜索(Breadth-First-Search)DFS和BFS的对比DFS使用栈(stack)来实现,BFS使用队列(queue)来实现DFS所需要......
  • 基于Astar算法的栅格地图目标最短路径搜索算法MATLAB仿真,带GUI界面
    1.算法描述       Astar算法是一种图形搜索算法,常用于寻路。它是个以广度优先搜索为基础,集Dijkstra算法与最佳优先(bestfit)算法特点于一身的一种算法。它通过......
  • 基于GA算法的TSP最短路径搜索matlab仿真
    1.算法描述(1)编码:将问题的候选解用染色体表示,实现解空间向编码空间的映射过程。遗传算法不直接处理解空间的决策变量,而是将其转换成由基因按一定结构组成的染色体。编码方......
  • 【DFS】LeetCode 108. 将有序数组转换为二叉搜索树
    题目链接108.将有序数组转换为二叉搜索树思路类似于二分搜索,定位到数组中间mid,然后左边的子数组构成左子树,右边的子数组构成右子树,mid处的数字构成根结点。递归构建......
  • 【DFS】LeetCode 669. 修剪二叉搜索树
    题目链接669.修剪二叉搜索树思路若root.val小于边界值low,则root的左子树必然均小于边界值,我们递归处理root.right即可;若root.val大于边界值high,则root的......
  • 【DFS】LeetCode 98. 验证二叉搜索树
    题目链接98.验证二叉搜索树思路依据BST的定义:左子树的结点都比根结点小,右子树的结点都比根结点大。我们在递归过程中传递根节点的值,判断当前结点值与根结点值的大小......
  • 【数据结构与算法】图论算法(C++实现)
    一些基本概念图一个图\(G=(V,E)\)由顶点集V和边集E组成。每一条边就是一副顶点对\((u,v)\),其中\(u,v\inV\)。顶点u和顶点v邻接当且仅当\((u,v)\inE\)......