匹配及其相关问题(二)
2015-12-31 21:22
127 查看
前言:
第一篇博客描述了一些与匹配相关的基本概念,下面来正式介绍匹配算法。这篇博客是比较久之前写的,主要介绍二分图最大匹配(二分图最大边独立)算法的匈牙利算法,许多匹配算法都是基于这个算法的思想进行改进的,匈牙利算法的时间复杂度大概是O( E * √V )。
简介:
匈牙利算法,由匈牙利数学家Edmonds与1965年提出,属于比较早期的一个算法。算法的核心在于寻找增广路径,是一种用增广路径求解二分图最大匹配的算法。
情景说明:
我们首先给出问题的具体模型:
有n个女生和m个男生,每个女生要选一个男生作为自己的舞伴,而且每个女生有一个或几个心仪的男生,男生没有选择权。问最多可以凑成多少对男女一起跳舞?
我们画个图举个例子,假设是4个女生和4个男生:
图中蓝色圆圈表示女生,红色圆圈表示男生,蓝色直线代表这两个人可以配对。从图中可以清晰的看到,这个图是一个二分图G,我们的目标是要找一个最大匹配M。这个最大匹配是原图的一个子图,包含所有的结点,而且每个结点的度最多为一。
算法流程:
如果没有学过网络流相关的算法的话,可能立马就会想到深搜算法了吧,但是这算法的时间复杂度是指数级别的,所以在点多的情况就必然会超时,所以我们需要一个高效的算法来解决这种问题。接下来将讲述匈牙利算法的算法流程:
1、准备工作
第一件事是建图,可以用邻接矩阵来存储;第二件事是开两个数组vis和pre,大小跟女生的人数一样即可,vis用来记录结点是否被访问过,pre数组用来保存当前的匹配情况;
2、对每个结点深搜寻找增广路径
在网络流里面,增广路径是指可以扩充当前流量的一条从源点到汇点的路径。匈牙利算法其实也是用网络流的思想来做的,这里的增广路的意义我们用个图来说明:
还是用的刚刚的图,假设我们当前匹配了两对,在图中用红色线表示匹配成对的边,接下来我们将要寻找第三个蓝结点的匹配:
我们可以看出,能和第三个蓝色结点匹配的只有第二个红色结点,然而该红色结点已经被第一个蓝色结点匹配了,如果不拆散他们,第三个结点将找不到匹配。这个时候,我们需要寻找一条增广路径:
如上图,黄色直线就代表当前一条增广路径,增广路径有几个特点:
1)长度为奇数;
2)偶数边为空闲边,奇数边为已匹配的边。
只要能找到增广路,就说明匹配还可以扩大。实际实现一般用深搜或宽搜。
3、重复第2步n次(n为女生数量)
4、得到最大二分图匹配
代码:
算法时间复杂度: O( E * √V )
第一篇博客描述了一些与匹配相关的基本概念,下面来正式介绍匹配算法。这篇博客是比较久之前写的,主要介绍二分图最大匹配(二分图最大边独立)算法的匈牙利算法,许多匹配算法都是基于这个算法的思想进行改进的,匈牙利算法的时间复杂度大概是O( E * √V )。
简介:
匈牙利算法,由匈牙利数学家Edmonds与1965年提出,属于比较早期的一个算法。算法的核心在于寻找增广路径,是一种用增广路径求解二分图最大匹配的算法。
情景说明:
我们首先给出问题的具体模型:
有n个女生和m个男生,每个女生要选一个男生作为自己的舞伴,而且每个女生有一个或几个心仪的男生,男生没有选择权。问最多可以凑成多少对男女一起跳舞?
我们画个图举个例子,假设是4个女生和4个男生:
图中蓝色圆圈表示女生,红色圆圈表示男生,蓝色直线代表这两个人可以配对。从图中可以清晰的看到,这个图是一个二分图G,我们的目标是要找一个最大匹配M。这个最大匹配是原图的一个子图,包含所有的结点,而且每个结点的度最多为一。
算法流程:
如果没有学过网络流相关的算法的话,可能立马就会想到深搜算法了吧,但是这算法的时间复杂度是指数级别的,所以在点多的情况就必然会超时,所以我们需要一个高效的算法来解决这种问题。接下来将讲述匈牙利算法的算法流程:
1、准备工作
第一件事是建图,可以用邻接矩阵来存储;第二件事是开两个数组vis和pre,大小跟女生的人数一样即可,vis用来记录结点是否被访问过,pre数组用来保存当前的匹配情况;
2、对每个结点深搜寻找增广路径
在网络流里面,增广路径是指可以扩充当前流量的一条从源点到汇点的路径。匈牙利算法其实也是用网络流的思想来做的,这里的增广路的意义我们用个图来说明:
还是用的刚刚的图,假设我们当前匹配了两对,在图中用红色线表示匹配成对的边,接下来我们将要寻找第三个蓝结点的匹配:
我们可以看出,能和第三个蓝色结点匹配的只有第二个红色结点,然而该红色结点已经被第一个蓝色结点匹配了,如果不拆散他们,第三个结点将找不到匹配。这个时候,我们需要寻找一条增广路径:
如上图,黄色直线就代表当前一条增广路径,增广路径有几个特点:
1)长度为奇数;
2)偶数边为空闲边,奇数边为已匹配的边。
只要能找到增广路,就说明匹配还可以扩大。实际实现一般用深搜或宽搜。
3、重复第2步n次(n为女生数量)
4、得到最大二分图匹配
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n,m,ans,a[105][105],v[105],pre[105]; bool dfs(int index) { for(int i=1;i<=m;i++) { if(!v[i]&&a[index][i]) { v[i]=1; if(!pre[i]||dfs(pre[i])) { pre[i]=index; return 1; } } } return 0; } void hungary() { for(int i=1;i<=n;i++) { memset(v,0,sizeof(v)); if(dfs(i)) ans++; } } int main() { while(~scanf("%d %d",&n,&m)) { memset(a,0,sizeof(a)); memset(pre,0,sizeof(pre)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); ans=0; hungary(); printf("%d\n",ans); } return 0; }
算法时间复杂度: O( E * √V )
相关文章推荐
- 详细了解HTML标签内容模型
- 完整和增量备份MySQL脚本
- Things Need To Be Done in 2016
- 个人年终总结
- UVa 10603 BFS+优先队列
- Quest Central for db2 安装图解
- TCP协议采用三次握手建立链接与断开链接
- HTTP与HttpServlet
- Win7下使用VMware Workstation 12 Pro安装OS X 10.8(2015-12-30 10:28)
- MyEclipse内存不足问题
- 08 将奇数排在偶数之前
- ajax请求过程中下载文件在火狐下的兼容问题
- 总结
- Java关键字(一)this与super关键字
- 高效看源代码网络汇总
- 揭秘阿里服务互联网金融的关系数据库——OceanBase
- Dx warning: Ignoring InnerClasses attribute for an anonymous inner class
- 转载使用 ContentObsever 拦截短信,获取短信内容
- .net2.0用TLS1.2+TCP Stream访问https网站
- linux 内核编译 传统方法和新方法