二分图的最大匹配问题(匈牙利算法)
最近在研究二分图问题,有很多东东还是不熟悉!边学习边完善!
【二分图】图中的顶点可以分为两个不相交的点集u和v,因此,二分图中的每个边都是u中的一个点连接v中的一个点。因为u与v不相交,所以图中不存在环。
【二分图的匹配】给定一个二分图G,M为G边集的一个子集,如果M满足当中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
【二分图的最大匹配】包含边数最多的匹配就是最大匹配。(比如,一个二分图中有三个匹配,即经过求最大匹配算法计算后有三个匹配,那么这个二分图的最大匹配数就是3)
【匈牙利算法】计算最大匹配的一种算法:
算法的理论基础:一个匹配为最大匹配当且仅当匹配中不存在交错路。(所以二分图的求解过程就是一个消除交错路的过程)
交错路:这样的一条路径,在二分图中,它的起点和终点都是都是未匹配的点,它的路径经过的一条连线是一条没被匹配的、一条已经匹配过的,这样交替的出现。也称增广路。
算法过程:将图左边的点逐个与右边的点进行检查,如果右边的点没有匹配过,那么就将它和左边这个点匹配,匹配数加1:如果匹配过但该点存在于一条交错路中(增广路),显然路径里没被匹配的连线比已经匹配了的连线多一条,于是修改匹配图,把路径里所有匹配过的连线去掉匹配关系,把没有匹配的连线变成匹配的,这样匹配数就比原来多1个。不断执行上述操作,直到找不到交错路(增广路径)为止。这时,就得到了最大的匹配数。
PS:
匈牙利算法只需要以每个节点为起点找一次增广路即可求得最大匹配,寻找增广路的复杂度为O(E),总的复杂度为O(VE)
用c/c++语言描述一下匈牙利算法的过程!
程序中涉及的变量说明:n为二分图的左部分顶点个数(顶点标号1-n)、m为二分图的右部分顶点个数(顶点标号为1-m),k为左右顶点的配对关系个数(保存在match二维数组中);
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define N 150 int visit[N]; int mark[N]; int match[N][N]; int n,m,k; int dfs(int x) { int i; for(i=1;i<=m;i++)//对左边的节点x与右边的节点进行逐一检查 { if(!visit[i]&&match[x][i]) { visit[i]=1;//标记检查过的点 if(!mark[i]||dfs(mark[i]))//如果右边的点没有被匹配或者匹配了但是存在交错路的 { mark[i]=x;//修改匹配关系 return 1; } } } return 0; } int main() { int i,j; while(cin>>n>>m>>k) { memset(mark,0,sizeof(mark)); memset(match,0,sizeof(match)); for(i=1;i<=k;i++) { int a,b; cin>>a>>b; match[a][b]=1;//标记当前匹配关系 } int max=0; for(j=1;j<=n;j++)//对做部分顶点逐个进行遍历 { memset(visit,0,sizeof(visit)); if(dfs(j)) max++; } cout<<max<<endl; } return 0; }
以上,便是匈牙利法求解二分图的最大匹配问题!不足之处,多多交流!
post by heat nan @2013-03-26
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?