C++图论 最小生成树和二分图问题总结

news2024/11/17 6:03:23

目录

一、最小生成树

(一)Prim朴素版

思路

练习题

代码

(二)kruskal算法

练习题

代码

 二、二分图

(一)染色法判定二分图

练习题

代码

(二)匈牙利算法

练习题

代码


一、最小生成树

(一)Prim朴素版

时间复杂度:O(n^2)

思路

① 初始化邻接矩阵和dist数组为\infty

② 进行n次循环,将n个点加入S集合
③ 找出不在集合中的离集合最近的点
④ 将点加入S集合,并用s集合更新剩下的点到集合的距离

区别
Prim算法与Dijkstra算法的代码有些相似,不同的是
① st数组表示的是点已经在生成树中,而Dijkstra算法st数组表示的是点是否已经确定了最短路径
② 第一个点到集合的权值为0,所以i为0时不用加上权值
③ 更新时是更新到集合(最小生成树)的最短边,所以min中不用加上dist[t] 

④ dist数组在Prim算法中表示的是一个点到最小生成树集合中所有点的最短距离,而在Dijkstra算法中表示的是点到源点的最短距离

练习题

给定一个 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≤10^5,
图中涉及边的边权的绝对值均不超过 10000。

输入样例:

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

输出样例:

6

代码

#include<iostream>
#include<cstring>
using namespace std;
const int N = 510;
int g[N][N], dist[N]; //稠密图用邻接矩阵存储
bool st[N];
int n, m, res;
void prim() {
    memset(dist, 0x3f, sizeof dist); //dist初始化为0x3f3f3f3f
    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(dist[t] == 0x3f3f3f3f) {
            res = 0x3f3f3f3f;
            return;
        }
        //先加入res再去for循环更新,因为可能有负环,那么会把自己变小,而最小生成树是不能包含负环的
        res += dist[t];
        st[t] = true;
        // 用t去更新其他的边到最小生成树集合的距离
        for(int j = 1 ; j <= n ; j ++) {
            dist[j] = min(dist[j], g[t][j]);
        }
    }
}
int main() {
    cin >> n >> m;
    int u, v, w;
    memset(g, 0x3f, sizeof g);
    while(m --) {
        scanf("%d%d%d",&u,&v,&w);
        g[u][v] = g[v][u] = min(g[u][v], w); //无向图存储两条边,有重边存储最短边
    }
    prim();
    if(res == 0x3f3f3f3f) puts("impossible");
    else cout << res << endl;
    return 0;
}

(二)kruskal算法

主要用于稀疏图,时间复杂度为O(mlogn)
思想:对边权进行排序后,按顺序从小到大,遇到一条边的两个结点不在同一个连通块中(借助并查集)的话,就加入结果并连接起来

步骤
① 对并查集数组p和边结构体初始化
② 对边结构体进行排序
③ 从小到大选取边,不在同一个连通块的话则连接起来并加入res,并计算加入了的边的条数
④ 判断是否有n条边,有的话则整个图是连通的

练习题

给定一个 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≤10^5,
图中涉及边的边权的绝对值均不超过 10000。

输入样例:

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

输出样例:

6

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5+5;
struct Edge{
    int a, b, c;
//    bool operator< (const Edge &W) const {
//      return w < W.w;
//    }
}edges[N];
int p[N];
bool cmp(Edge a, Edge b) {
    return a.c < b.c;
}
int find(int x) { // 并查集,查找祖先
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}
int main() {
    int n, m;
    cin >> n >> m;
    for(int i = 0 ; i <= n; i ++) p[i] = i; //每个点都是孤立的点
    for(int i = 0 ; i < m;i ++) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        edges[i] = {a, b, c};
    }
    sort(edges, edges + m, cmp); //从小到大排序
    int res = 0, cnt = 0;
    // 遍历边结构体,如果a和b未连接,也就是a和b的边还未加入最小生成树,那么加入并记录
    for(int i = 0 ; i < m; i ++) {
        int a = find(edges[i].a), b = find(edges[i].b);
        if(a != b) {
            p[a] = b;
            res += edges[i].c;
            cnt ++;
        }
    }
    //不足n-1条边代表没有最小生成树
    if(cnt < n - 1) puts("impossible");
    else cout << res << endl;
    return 0;
}

 二、二分图

(一)染色法判定二分图

深搜进行判断二分图,用1和2进行染色。
二分图不一定是连通图,也可能是非连通图。

练习题

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

请你判断这个图是否是二分图。

输入格式

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

接下来 m 行,每行包含两个整数 u 和 v,表示点 u 和点 v 之间存在一条边。

输出格式

如果给定图是二分图,则输出 Yes,否则输出 No

数据范围

1≤n,m≤10^5

输入样例:

4 4
1 3
1 4
2 3
2 4

输出样例:

Yes

代码

#include<iostream>
#include<cstring>
using namespace std;
const int N = 2e5+5; //无向图,需要存储两条边,所以双倍
int h[N], e[N], ne[N], idx; //稀疏图用邻接表
int color[N]; //判断是否已经被染色了,且记录被1还是2染色
int n, m;
void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool dfs(int x, int c) {
    color[x] = c; //染色
    for(int i = h[x]; i != -1; i = ne[i]) { //
        int j = e[i];
        //如果没填过就递归填一下色,或者如果颜色和要填的颜色相同,代表冲突,不是二分图
        if((!color[j] && !dfs(j, 3-c) )|| color[j] == c) {
           return false; 
        }
    }
    return true;
}
int main() {
    cin >> n >> m;
    memset(h, -1, sizeof h); //初始化头节点
    int a, b;
    while(m--) {
        scanf("%d%d",&a, &b);
        add(a, b), add(b, a); //无向图
    }
    bool flag = true;
    //二分图不一定是连通图,也可能是非连通图。这也是这个for循环存在的意义
    for(int i = 1; i <= n; i ++ ) {
        if(!color[i]) {
            //不连通,所以每个连通块都从1开始就好
            if(!dfs(i, 1)) {
                flag = false; //有冲突
                break;
            }
        }
    }
    if(!flag) puts("No");
    else puts("Yes");
    return 0;
}

(二)匈牙利算法

匈牙利算法基础知识可以查阅这篇文章:匈牙利算法详解_Amelie_xiao的博客-CSDN博客_匈牙利算法

  • 匈牙利算法(Hungarian algorithm),即图论中寻找最大匹配的算法
  • 匈牙利算法(Hungarian algorithm),主要用于解决一些与二分图匹配有关的问题。

可以比喻成男女匹配的过程

第一个男生和第二个男生都顺利和女生匹配了,此时第三个男生匹配到的是已经心有所属的女生,且这个男生没有别的钟情的女生了,那么为了获得最大匹配数量,我们可以看一下与这女生匹配的一号男生有没有其他可以匹配的女生,发现有,那么将1号男生转换目标,然后三号男生就能顺利牵手了,匹配数也就+1了(绿色线代表取消了)

演示匈牙利算法整个配对的递归过程

练习题

给定一个二分图,其中左半部包含 n1 个点(编号 1∼n1),右半部包含 n2 个点(编号 1∼n2),二分图共包含 m 条边。

数据保证任意一条边的两个端点都不可能在同一部分中。

请你求出二分图的最大匹配数。

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

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

输入格式

第一行包含三个整数 n1、 n2 和 m。

接下来 m 行,每行包含两个整数 u 和 v,表示左半部点集中的点 u 和右半部点集中的点 v 之间存在一条边。

输出格式

输出一个整数,表示二分图的最大匹配数。

数据范围

1≤n1,n2≤500,
1≤u≤n1,
1≤v≤n2,
1≤m≤10^5

输入样例:

2 2 4
1 1
1 2
2 1
2 2

输出样例:

2

代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 505, M = 2 * 1e5;
int n1, n2, m;
int h[N], e[M], ne[M], idx; //从题意上看是稠密图,可用邻接矩阵或邻接表
int match[N]; //记录女生找的男生是谁,方便下一次的回溯
bool st[N];
void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a] , h[a] = idx++;
}
bool find(int x) {
    for(int i = h[x]; i != -1; i = ne[i]) {
        int j = e[i];
        if (!st[j]) //防止重复查询,比如为与她相匹配的男生找下家肯定不能还找那个女生了
        {
            st[j] = true; 
            //如果j这个女生没匹配过或者可以将与她相匹配的男生找下家的话,那么就与当前的男生匹配
            if (match[j] == 0 || find(match[j]))
            {
                match[j] = x;
                return true;
            }
        }
    }
    return false;
}
int main() {
    cin >> n1 >> n2 >> m;
    memset(h, -1, sizeof h);
    int a, b;
    while(m --) {
        scanf("%d%d",&a,&b);
        add(a, b) ; //左边部分的点指向右半部分,相当于有向边了
    }
    int res = 0;
    for(int i = 1 ;i <= n1; i ++) { //遍历左边所有的点
        memset(st, false, sizeof st); //每次要重置st数组
        if(find(i)) res ++;
    }
    cout << res << endl;
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/128946.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSDN官方开发工具利器猿如意实测

目录前言一.ChatGPT二.效率工具三.开发工具四.教程文档五.一行代码六.总结前言 猿如意 是CSDN官方2022年推出的面向程序员效率工具集合&#xff0c;里面包含非常实用的小工具&#xff08;如Linux命令查询、语音合成、Json格式化、Host切换、文字转图片、Postman、图片处理等&a…

Linux 快照 (snapshot) 原理与实践(一) 快照基本原理

文章目录0. 背景1. 如何理解快照(snapshot)?2. 快照 (snapshot) 的原理2.1 全量快照1. 克隆 (Clone)2. 镜像分离 (Split Mirror)2.2 增量快照1. 写时拷贝(Copy-On-Write)**写数据****读数据****优缺点**2. 写时重定向 (Redirect-On-Write)**写数据****读数据**优缺点3. Linux …

电脑免费录屏软件有哪些?5款视频录制软件免费版

在日常生活工作与学习中&#xff0c;都会经常遇到需要录制屏幕的情况&#xff0c;比如录制线上会议纪要记录、老师授课内容、游戏画面、线上直播等&#xff1b;在众多网络网友录屏软件分享下&#xff0c;有哪些电脑录屏软件是好用的&#xff1f;今天小编就给大家分享5款觉得还不…

最短编辑距离

最短编辑距离一、问题描述二、思路分析1、状态转移方程&#xff08;1&#xff09;状态表示&#xff08;2&#xff09;状态转移2、循环及初始化&#xff08;1&#xff09;循环设计&#xff08;2&#xff09;初始化处理三、代码实现一、问题描述 二、思路分析 这道题是一道DP的问…

oh my 毕设-人体姿态估计-简介应用场景

毕设题目为人体姿态估计&#xff0c;之前主要关注在目标检测上&#xff0c;这方面不太熟悉&#xff0c;于是想做一个系列专栏&#xff0c;从0到1学习姿态估计。 参考于大佬-同济子豪兄 姿态估计本质是关键点检测。 人体姿态的估计常常首先预测出人体各个关键点的位置坐标&am…

160.相交链表

给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回结果后&…

开启 kerberos 后,HiveServer2 的 webui 没有内容的解决方案

开启 kerberos 后&#xff0c;HiveServer2 的 webui 没有内容。页面如下&#xff0c;可以打开&#xff0c;但是即便已经有会话&#xff0c;也有SQL执行&#xff0c;这里一直这样。 1. 原因分析 1.1 hiveserver2.jsp 以Active Sessions 的内容为例&#xff0c;./service/src…

electron起步基本和electron打包 无脑步骤(修改electron图标)

1.安装 yarn add electron --dev 和 yarn add nodemon --dev 2.在package.json 写main入口和启动脚本 "main":"main.js", "start": "nodemon --exec electron . --watch ./ --ext .js,.html,.css,.vue" "license": "…

oracle在本地创建数据库和导入DMP数据泵

第一步&#xff1a;创建本地数据库 databse Configuration Assistant&#xff0c;创建数据库。 下一步之后完成。 通常在创建数据库时会报错&#xff0c;如图&#xff0c;直接跳过&#xff0c;在net manager的Listener下添加一个新的地址&#xff0c;协议名填写警告日志中Prot…

关于mmpose

为什么是关于mmpose呢&#xff0c;因为我菜。本文仅做记录使用&#xff0c;也就是说&#xff0c;写的不一定对&#xff0c;欢迎大佬批评指正。 我只想知道这种关键点检测是如何标注的&#xff0c;数据集是如何搞的&#xff0c;全网居然都找不到&#xff0c;付费资源我不配&…

Android设计模式详解之装饰模式

前言 装饰模式也称为包装模式&#xff0c;结构型设计模式之一&#xff1b; 定义&#xff1a;动态地给一个对象添加一些额外的职责。就增加功能来说&#xff0c;装饰模式生成子类更为灵活&#xff1b; 使用场景&#xff1a;需要透明且动态地扩展类的功能时&#xff1b; UML类…

零经验出海报单,看跨境电商小白如何在Starday突出重围

随着大数据、云计算等一系列新颖先进的技术概念引入&#xff0c;全球经济市场呈现出以往难以想象的活跃&#xff0c;世界各地的贸易订单都可以借助互联网渠道在数秒内完成全流程。“跨境电商”这一概念正是全球互联网技术普及应用下的附属品&#xff0c;更是经济全球化时代发展…

第五章. 可视化数据分析图表—Seaborn图表(线性回归模型,箱型图,核密度图,提琴图)

第五章. 可视化数据分析图 5.7 Seaborn图表 Seaborn是一个基于Matplotlib的高级可视化效果库&#xff0c;偏向于统计图表&#xff0c;主要针对的是数据挖掘和机器学习中的变量特征选取&#xff0c;相比Matplotlib&#xff0c;他的语法相对简单&#xff0c;但是具有一定的局限性…

《Java高并发与集合框架》第三部分在高并发场景中工作的集合

《Java高并发与集合框架》第三部分在高并发场景中工作的集合前言1.高并发场景中的List、Map和Set集合1.1 CopyOnWriteArrayList1.2 CopyOnWriteArrayList不支持的使用场景1.3 CopyOnWriteArrayList主要方法1.4 java.util.Collections.synchronizedList()方法的补充作用1.4.1 Co…

Allegro如何实现交换pin操作详细指导

Allegro如何实现交换pin操作详细指导 在做PCB设计的时候,换pin是用的较多的功能,换pin可以让线序更加的顺,方便布线。但是前提是确保网络的交换是被允许的 下面用下图为例介绍Allegro中是如何实现交换pin的 具体操作如下 选择File选择Export-Libraries

2022年终,盘点IT行业全年10大事件

白云苍狗&#xff0c;一眨眼&#xff0c;2022年就来到了尾声。这一年里&#xff0c;IT行业发生了不少的大事。有喜有忧&#xff0c;令人目不暇接&#xff0c;显现出IT行业风云变幻的一面。 本期&#xff0c;知了姐为大家整理了近一年来&#xff0c;IT行业发生的10件大事。 NO…

Linux下安装mysql

下载地址&#xff1a; https://dev.mysql.com/downloads/mysql/ 1.解压mysql 文件包&#xff0c;解压路径/home/mysql tar -zxvf mysql-8.0.31-linux-glibc2.12-x86_64.tar 2.编写配置 [client] #password your_password port 3306 socket /home/mysql/…

无线网络监控分析工具

多年来&#xff0c;网络设备已经从房间大小的机器急剧转变为小型便携式设备。随着设备尺寸发生巨大变化&#xff0c;将这些设备相互连接所涉及的技术也发生了巨大变化。这些剧烈变化的结果是无线网络的形成。无线网络的优势在于网络中的各种设备之间不需要物理连接。此外&#…

GoLang ~ 远程调试

前提条件 在编译go项目时&#xff0c;使用​​go build -gcflags "all-N -l"​​&#xff0c;关闭内联优化&#xff0c;以支持debug。 关于​​-gcflags "-N -l"​​参数的解释&#xff1a; 编译时&#xff0c;如果编译的结果需要gdb调试则使用参数​​-…

ASEMI整流桥2W10,DB107S和KBP307封装参数对比

编辑-Z ASEMI整流桥2W10&#xff0c;DB107S和KBP307是很常见的型号&#xff0c;今天就把整流桥2W10&#xff0c;DB107S和KBP307的封装参数对比一小&#xff0c;以便大家在选型时有更好的参考。 2W10参数&#xff1a; 型号&#xff1a;2W10 封装&#xff1a;WOB-4 最大重复峰…