二部图问题

目录

一、介绍

 二、染色算法的实现

三、无权二部图中的最大匹配

四、有权二部图中的最大匹配

五、稳定婚配问题 


一、介绍

二部图是一种特殊的图,其中所有的节点可以被分成两个不相交的集合,使得图中的每条边连接的两个节点分属于不同的集合。换句话说,二部图可以被划分为两个独立的顶点集合,且所有边的两个节点分别属于这两个集合。

二部图可以用来描述许多现实世界中的问题,例如婚姻稳定性问题、任务分配等。因此,判定一个图是否是二部图的问题具有重要的意义。

常用的判定二部图的算法之一是基于深度优先搜索(DFS)的染色算法:

  1. 从任意一个节点开始,将该节点染成一个颜色(例如红色)。
  2. 遍历该节点的所有邻居节点,如果某个邻居节点未被染色,则将其染成与当前节点不同的颜色(例如蓝色)。
  3. 对每个邻居节点,再递归地执行步骤2。
  4. 如果在遍历的过程中遇到某个邻居节点已经被染成与当前节点相同的颜色,则说明该图不是二部图。
  5. 如果成功对图中的所有节点都进行了染色并没有出现步骤4的情况,则说明该图是二部图。

如果使用染色算法判定二部图,则时间复杂度为 O(V+E),其中 V 是节点的数量,E 是边的数量。这是因为每个点和每条边仅会进出一次。

另外,二部图可以用邻接矩阵或邻接表的形式表示,并且可以使用其他算法和技术来解决和优化相关问题,例如匹配问题和最大权匹配问题等。

总结来说,二部图是一种特殊的图,可以被划分为两个独立的节点集合,且图中的每条边都连接两个不同的节点集合。判定一个图是否是二部图的染色算法是常用的方法,时间复杂度为 O(V+E)。

 二、染色算法的实现

以下是使用 MATLAB 实现二部图判定算法的例子代码:

function isBipartite = checkBipartite(graph)numNodes = size(graph, 1);colors = zeros(numNodes, 1); % 用于存储节点的颜色,0表示未染色,1和-1表示染成的两种颜色% 从节点1开始进行深度优先搜索if dfs(1, graph, 1, colors)isBipartite = true;elseisBipartite = false;end
endfunction isBipartite = dfs(node, graph, color, colors)% 染色colors(node) = color;% 遍历当前节点的邻居节点neighbors = find(graph(node, :));for i = 1:length(neighbors)neighbor = neighbors(i);% 如果邻居节点未染色,就染成与当前节点不同的颜色,并递归地对邻居节点进行DFSif colors(neighbor) == 0if ~dfs(neighbor, graph, -color, colors)isBipartite = false;return;end% 如果邻居节点已经染色,并且颜色相同于当前节点,说明该图不是二部图elseif colors(neighbor) == colorisBipartite = false;return;endendisBipartite = true;
end

使用该代码,你需要构建一个邻接矩阵表示的图,其中矩阵的每个元素 graph(i, j) 表示节点 i 和节点 j 之间是否有边。如果图是二部图,函数 checkBipartite 返回值为 true,否则返回值为 false。

例如,下面是一个简单的例子:

% 构建邻接矩阵表示的图
graph = zeros(4); % 创建一个4个节点的图
graph(1, 2) = 1;  % 添加边
graph(2, 1) = 1;
graph(2, 3) = 1;
graph(3, 2) = 1;
graph(3, 4) = 1;
graph(4, 3) = 1;% 判定该图是否为二部图
isBipartite = checkBipartite(graph);if isBipartitedisp("该图是二部图");
elsedisp("该图不是二部图");
end

在这个例子中,构建了一个包括4个节点和3条边的图。经过二部图判定算法的判断,输出结果为 “该图是二部图”。你可以根据需要修改邻接矩阵来进行测试。

三、无权二部图中的最大匹配

这个问题其实也可以转化为最大流问题。我们这用贪心的思想,步骤如下

  1. 初始化一个空的匹配集合;
  2. 对于每一个未匹配的左边节点,遍历它的所有可连边右边节点,并将其中一个作为该左边节点的匹配;
  3. 如果右边节点已经被匹配,则进行以下比较:
    • 如果右边节点已经被匹配,但是已匹配节点的度数大于当前节点,则更改匹配;
    • 反之,保留原有结果,不进行匹配;
  4. 匹配过程结束后,返回当前匹配集合。

这个策略的基本思路是从左到右地扫描无权二部图,对于每个左端节点,选择和它直接相连的一个右端节点进行匹配操作,直到无法找到增广路径为止。

此算法的时间复杂度为 O(V^2),其中 V 是二部图的顶点数。缺点也十分明显,即可能无法找到最优解

以下是使用 MATLAB 实现贪心算法求解无权二部图最大匹配的例子代码:

function maxMatching = greedyMatching(graph)numNodes = size(graph, 1);maxMatching = 0;matching = zeros(numNodes, 1); % 存储节点的匹配情况,0 表示未匹配,非零表示匹配的节点编号for u = 1:numNodesif matching(u) == 0 % 当前节点未匹配neighbors = find(graph(u, :)); % 找到与当前节点相连的节点% 遍历所有可匹配的右边节点for i = 1:length(neighbors)v = neighbors(i);% 如果节点 v 未匹配,直接进行匹配if matching(v) == 0matching(v) = u;maxMatching = maxMatching + 1;break;% 如果节点 v 已匹配,比较度数后决定是否更新匹配elseif sum(graph(:, v)) > sum(graph(:, matching(v)))matching(v) = u;break;endendendend
end

四、有权二部图中的最大匹配

其实有权二部图的最大匹配和最小匹配是可以相互转化的,下面介绍的算法是来寻找最小匹配的,在权值前面加一个负号就可以转换为最大匹配。

对于有权二部图的最大匹配问题,我们一般采用匈牙利算法 (Hungarian Algorithm),先来介绍匈牙利算法。

匈牙利算法(Hungarian Algorithm)是一种经典的用于解决最大权值二分图最大匹配问题的算法。它由匈牙利数学家Dénes Kőnig于1931年提出,后来由Eugene L. Lawler在1961年重新发现并进行了改进。

匈牙利算法的基本思想是通过寻找增广路径来逐步构建最大匹配。增广路径是从一个未匹配的左顶点开始,通过交替考察边的方式找到一个未匹配的右顶点,再找一个已匹配的左顶点,然后继续找未匹配的右顶点,如此往复,直到找不到延伸路径为止。

算法的具体步骤如下:

  1. 初始化一个空匹配;
  2. 对每个未匹配的左顶点u,使用DFS(深度优先搜索)或BFS(广度优先搜索)找到一条增广路径;
  3. 如果找到增广路径,则根据增广路径的方向修改匹配,即反转路径中已匹配的边和未匹配的边;
  4. 如果找不到增广路径,则算法结束,当前匹配就是最大匹配。

匈牙利算法的时间复杂度为O(V^3),其中V是二分图中的顶点数。虽然算法在理论上的复杂性较高,但实际上被证明是非常有效的,特别是在小规模和中等规模的问题上。

下面上代码

function [max_matching, matching] = hungarian_algorithm(graph)num_nodes = size(graph, 1);matching = -1 * ones(1, num_nodes);  % 存储节点的匹配情况,-1表示未匹配,非负整数表示匹配的节点编号function result = dfs(node)for neighbor = 1:num_nodesif graph(node, neighbor) && ~visited(neighbor)visited(neighbor) = true;if matching(neighbor) == -1 || dfs(matching(neighbor))matching(neighbor) = node;result = true;return;endendendresult = false;endmax_matching = 0;for node = 1:num_nodesvisited = false(1, num_nodes);if dfs(node)max_matching = max_matching + 1;endendend

你可以通过调用 hungarian_algorithm 函数,传入一个邻接矩阵 graph,来求解二分图的最大匹配。函数将返回最大匹配的数量 max_matching 和匹配结果 matching,其中 matching 是一个向量,表示每个左顶点匹配的右顶点编号,值为 -1 表示未匹配。

以下是一个使用示例:

% 构建二分图邻接矩阵
graph = [0 1 0 0 1;1 0 1 1 0;0 1 0 1 0;0 1 1 0 0;1 0 0 0 1];% 使用匈牙利算法求解二分图最大匹配
[max_matching, matching] = hungarian_algorithm(graph);% 输出最大匹配结果
fprintf('最大匹配数: %d\n', max_matching);
for i = 1:length(matching)if matching(i) ~= -1fprintf('左顶点 %d 与右顶点 %d 匹配\n', i, matching(i));end
end

在上面的例子中,我们首先定义了一个二分图的邻接矩阵 graph,然后调用 hungarian_algorithm 函数来求解最大匹配。最后,我们输出最大匹配的数量和具体的匹配结果。

五、稳定婚配问题 

稳定婚配问题(Stable Marriage Problem)是一种经典的组合优化问题,它源自于数学家David Gale和Lloyd Shapley在1962年的研究。该问题描述了如何稳定地匹配两组个体(通常是男性和女性)之间的偏好。

假设有n个男性和n个女性,每个男性可以按照对女性的偏好顺序对女性进行排名,同样,每个女性也可以对男性进行排名。稳定婚配问题的目标是找到一个婚配情况,使得没有两个人可以离开他们当前的配偶并配对在一起,形成一对"不稳定的"夫妻。

稳定婚配问题的一个经典解决方案是Gale-Shapley算法,也称为Deferred Acceptance Algorithm。该算法如下:

1. 初始化所有人都未婚,并且没有被拒绝的配偶。将所有男性列入“自由男性”列表。
2. 选择一个自由男性,让他向他在女性排名上最高的未婚女性求婚。
3. 如果该女性是未婚的,则接受求婚并将她与该男性匹配。如果该女性已经与另一男性匹配,比较该女性对当前男性和已匹配男性的偏好,并做出决定:如果她更喜欢当前男性,则与当前男性解除婚约,与新男性匹配;如果她更喜欢已匹配男性,则拒绝当前男性的求婚。
4. 将未婚的男性从自由男性列表中移除,并将被拒绝的求婚男性加入列表中。
5. 重复步骤2-4,直到所有男性都完成求婚过程。
6. 返回最终匹配结果。

Gale-Shapley算法保证了找到一个稳定的配对,即不存在两人可以配对在一起并不再与原先的配偶在一起的情况。而且,根据问题的设定,男性会更倾向于提出求婚,而女性则会根据自己的喜好作出决定。

稳定婚配问题不仅仅局限于男性和女性之间的匹配,它也可以应用于其他场景,比如求职者和职位的匹配,学生和学校的匹配等。

下面是一个用 MATLAB 实现稳定婚配问题(Gale-Shapley算法)的简单示例代码:

function [matches] = stableMatching(menPrefs, womenPrefs)n = size(menPrefs, 1);men = 1:n;women = (n+1):(2*n);matches = zeros(1, 2*n);proposals = zeros(1, 2*n);while any(matches(men) == 0)freeMan = men(matches(men) == 0, 1); % 找到没有匹配的男性for i = 1:length(freeMan)man = freeMan(i);woman = menPrefs(man, proposals(man) + 1); % 找到男性当前喜欢的女性proposals(man) = proposals(man) + 1;if matches(woman) == 0 % 女性还没有匹配matches(man) = woman;matches(woman) = man;elsecurrentMan = matches(woman);if find(womenPrefs(woman, :) == man) < find(womenPrefs(woman, :) == currentMan) % 比较女性的偏好matches(man) = woman;matches(woman) = man;matches(currentMan) = 0;endendendend
end

使用示例:

menPrefs = [3 1 2; 1 3 2; 2 3 1]; % 男性对女性的偏好,每行代表一个男性的偏好顺序
womenPrefs = [2 1 3; 2 3 1; 3 1 2]; % 女性对男性的偏好,每行代表一个女性的偏好顺序matches = stableMatching(menPrefs, womenPrefs);

在这个例子中,有3个男性和3个女性。 menPrefs 矩阵表示了男性对女性的偏好,每行代表一个男性的偏好顺序,数字越小表示越喜欢;womenPrefs 矩阵表示了女性对男性的偏好,每行代表一个女性的偏好顺序。运行代码后,将得到匹配结果 matches,它是一个包含每个男性和女性配对的向量,索引1-3表示男性,索引4-6表示女性。

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

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

相关文章

什么是GIL锁,有什么作用?python的垃圾回收机制是什么样的?解释为什么计算密集型用多进程,io密集型用多线程。

1 什么是gil锁&#xff0c;有什么作用&#xff1f; 2 python的垃圾回收机制是什么样的&#xff1f; 3 解释为什么计算密集型用多进程&#xff0c;io密集型用多线程。 1 什么是gil锁&#xff0c;有什么作用&#xff1f; 1 GIL&#xff1a;Global Interpreter Lock又称全局解释器…

基于安卓android微信小程序的食谱大全系统

项目介绍 本文以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;它主要是采用java语言技术和mysql数据库来完成对系统的设计。整个开发过程首先对食谱大全进行需求分析&#xff0c;得出食谱大全主要功能。接着对食谱大全进行总体设计和详细设计。总体设…

源码升级gcc

wget https://ftp.gnu.org/gnu/gcc/gcc-8.1.0/gcc-8.1.0.tar.gztar -xzf gcc-8.1.0.tar.gzcd gcc-8.1.0/打开/contrib/download_prerequisites&#xff0c;查看依赖的库 wget http://mirror.linux-ia64.org/gnu/gcc/infrastructure/mpfr-3.1.4.tar.bz2 & wget http://mir…

实现高值医疗耗材智能化管理的RFID医疗柜解决方案

一、行业背景 医疗物资管理面临着一系列问题&#xff0c;如高值耗材种类激增导致准入标准弱化、信息追踪困难、管理责任不明确等&#xff0c;医院内部设备、财务和临床科室相互独立&#xff0c;兼容性不佳&#xff0c;高值耗材储备不足&#xff0c;缺乏合理的预警机制&#xf…

Java 21:最新特性、性能改进和语言发展

文章目录 模式匹配和模式变量新的记录类型生产者接口本地类型推断的扩展新的垃圾收集器动态CDS档案G1垃圾收集器的增强Java语言的持续发展性能改进和JEPJava 21的部署和使用Java 21的生态系统结语 &#x1f389;欢迎来到Java学习路线专栏~Java 21&#xff1a;最新特性、性能改进…

Postman接口Mock Servier服务器

近期在复习Postman的基础知识&#xff0c;在小破站上跟着百里老师系统复习了一遍&#xff0c;也做了一些笔记&#xff0c;希望可以给大家一点点启发。 应用场景&#xff1a;后端的接口还没有开发完成&#xff0c;前端的业务需要调用后端的接口&#xff0c;可以使用mock模拟。 一…

Android高级实践分享

以下是我学习过程中&#xff0c;觉得比较好的Android进阶高级实践&#xff0c;分享给大家&#xff0c;可能有些东西差异化比较大了&#xff0c;但是我也想经过这些实践&#xff0c;踩踩坑。等我搞完&#xff0c;给大家出一下实践教程 Android进阶之旅&#xff1a; https://ww…

终于有人把VMware虚拟机三种网络模式讲清楚了!

前段时间VMware更新了&#xff0c;你用上最新版了吗&#xff1f; 有几个网工在操作中遇到过各种各样的问题。 比如说由于公司服务器重启导致出现下面的问题&#xff1a;在Xshell里连接虚拟机映射时连接失败&#xff1b;能够连接上虚拟机的映射地址&#xff0c;但git pull时报…

电子电机行业万界星空科技MES解决方案

现在电子电机行业规模越来越大&#xff0c;也伴随着生产和管理成本走向变高的现象。针对这个问题&#xff0c;mes系统就成为各电子电机制造业的最优选择。 电子机电行业MES涵盖了从原材料采购到最终产品交付的整个过程&#xff0c;包括生产计划、物料管理、生产过程监控、质量…

CleanMyMac X“断网激活”真的可以吗?

CleanMyMac X帮助Mac系统进行垃圾清理&#xff0c;清除多余的缓存、应用程序等&#xff0c;在提高工作效率上起了很大的作用。但是随着对软件的需求不断增加&#xff0c;很多人开始研究通过捷径破解正版软件&#xff0c;但是是否能成功呢&#xff1f;今天小编就为大家揭开“断网…

【常见SQL报错及解决办法】个人记录,自用

ORA-00942: 表或视图不存在 现象&#xff1a;明明已经新建了视图&#xff0c;并提交了&#xff0c;直接查询的时候还是报了这个错 解决&#xff1a;视图名那加双引号&#xff0c;与建立的时候保持一致 --SELECT * FROM VIEW_NAME 报错&#xff0c;需要加双引号 SELECT * FR…

7-爬虫-中间件和下载中间件(加代理,加请求头,加cookie)、scrapy集成selenium、源码去重规则(布隆过滤器)、分布式爬虫

0 持久化(pipelines.py)使用步骤 1 爬虫中间件和下载中间件 1.1 爬虫中间件(一般不用) 1.2 下载中间件&#xff08;代理&#xff0c;加请求头&#xff0c;加cookie&#xff09; 1.2.1 加请求头(加到请求对象中) 1.2.2 加cookie 1.2.3 加代理 2 scrapy集成selenium 3 源码去重…

C++ 动态规划 DP教程 (一)思考过程(*/ω\*)

动态规划是一种思维方法&#xff0c;大家首先要做的就是接受这种思维方法&#xff0c;认同他&#xff0c;然后再去运用它解决新问题。 动态规划是用递推的思路去解决问题。 首先确定问题做一件什么事情&#xff1f; 对这件事情分步完成&#xff0c;分成很多步。 如果我们把整件…

【SpringBoot】序列化和反序列化介绍

一、认识序列化和反序列化 Serialization&#xff08;序列化&#xff09;是一种将对象以一连串的字节描述的过程&#xff1b;deserialization&#xff08;反序列化&#xff09;是一种将这些字节重建成一个对象的过程。将程序中的对象&#xff0c;放入文件中保存就是序列化&…

回顾 — SFA:简化快速 AlexNet(模糊分类)

模糊图像的样本 一、说明 在本文回顾了基于深度学习的模糊图像分类&#xff08;SFA&#xff09;。在本文中&#xff1a;Simplified-Fast-AlexNet (SFA)旨在对图像是否因散焦模糊、高斯模糊、雾霾模糊或运动模糊而模糊进行分类。 二、大纲 图像模糊建模简要概述简化快速 AlexNet…

vscode 快速打印console.log

第一步 输入这些 {// Print Selected Variabl 为自定义快捷键中需要使用的name&#xff0c;可以自行修改"Print Selected Variable": {"body": ["\nconsole.log("," %c $CLIPBOARD: ,"," background-color: #3756d4; padding:…

action3录制出来的LRF文件的正确打开方式

你会发现使用大疆的产品录制出来的视频会有两种格式&#xff1a;LRF和MP4 这个LRF文件是低分辨率、低码率的预览文件&#xff0c;非常适合预览。 这个文件可以直接通过修改文件后缀转化为.mp4格式

【R Error系列】r - fatal error : RcppEigen. h:没有这样的文件或目录

在头文件那要有 // [[Rcpp::depends(RcppEigen)]] 即&#xff1a; #include <Rcpp.h> #include <RcppEigen.h> using namespace Rcpp; using namespace Eigen;// [[Rcpp::depends(RcppEigen)]] // [[Rcpp::export]] 参考&#xff1a; r - fatal error: RcppEi…

14——1

这句话的意思是&#xff0c;如图中月份12天数23时&#xff0c;就是1223&#xff1b;当月份9天数2时&#xff0c;就是0902. 可以看到在上面给出的数组元素中&#xff0c;并没有连续挨在一起的2023数字元素——就有人可能输出答案0。 所以这里要看一下—— ——子序列的含义&…