匹配及其相关问题(三)
2016-04-05 22:24
267 查看
前言:
第二篇博客介绍了匈牙利算法解二分图最大匹配,这次我们需要应用这个算法来解决最小点覆盖与最大点独立问题。
基本定理:
根据博客(一),我们有以下定理:
定理3:二分图中,无孤立点,点覆盖数=边独立数(匹配数)
定理8:无向图中,无孤立点,最小点覆盖集与最大点独立集互补
我们这次需要使用这两个定理来解决最小点覆盖与最大点独立问题。
算法思路:
根据定理3,我们有点覆盖数等于匹配数,那么我们可以认为,最小点覆盖集与最大匹配之间有一种一一对应的关系。
最小点覆盖:
在求解完二分图匹配之后,我们可以知道现在二分图中已经没有增广路了,而且只存在两种边,第一种为两端都是已匹配点,第二种为一端已匹配、另一端未匹配。那么我们要找的最小点覆盖集肯定可以在所有的匹配点里找到,即对第一种边,随便挑一个点;对第二种边,挑匹配点。
那么我们怎么选这些匹配点呢?因为所有与未匹配点相连的点都应该是最小点覆盖集里的点,那么跟这些点匹配的点当然是不需要在最小点覆盖集里了。我们可以把二分图分成两部分,即左边和右边,我们可以使用匈牙利算法从未匹配点开始寻找增广路,对图中的点进行标记,最终左边未标记的点和右边标记了的点组成了最小点覆盖。
其实也可以分类讨论考虑最小点覆盖问题,即左边有未标记点和左边无未标记点。对于第一种情况,我直接左边的所有点组成的点集组成最小点覆盖;对于第二种情况,我们则是为了找到所有能覆盖未标记点所在的边而进行匈牙利的match操作,即我们发现最小点覆盖中不可能有这个点,于是就去找能够覆盖该点所有关联边的代替点集合。
最大点独立:
既然我们知道最小点覆盖,那么根据定理8,我们只需要求出最小点覆盖的补集就是最大点独立了,即标记了的左边点和未标记的右边点。
例题解析:
1、二分图最小点覆盖:
题目链接:UVA 11419
解题思路:
二分图最小点覆盖模板题。把每一行变成左边的点,每一列变成右边的点,这样就变成了最小点覆盖问题,可用上述算法解决。
代码:
2、二分图最大点独立:
题目链接:UVALIVE 4288
解题思路:
二分图最大点独立,因为只需要求点独立数,所以直接套用匈牙利算法即可。构图方面,把所有人分成两类,喜欢猫的和喜欢狗的,形成二分图,并把所有存在矛盾关系的人连一条边,即讨厌对方喜欢的动物或者喜欢对方讨厌的动物。
代码:
参考资料:
Matrix 67的博客
第二篇博客介绍了匈牙利算法解二分图最大匹配,这次我们需要应用这个算法来解决最小点覆盖与最大点独立问题。
基本定理:
根据博客(一),我们有以下定理:
定理3:二分图中,无孤立点,点覆盖数=边独立数(匹配数)
定理8:无向图中,无孤立点,最小点覆盖集与最大点独立集互补
我们这次需要使用这两个定理来解决最小点覆盖与最大点独立问题。
算法思路:
根据定理3,我们有点覆盖数等于匹配数,那么我们可以认为,最小点覆盖集与最大匹配之间有一种一一对应的关系。
最小点覆盖:
在求解完二分图匹配之后,我们可以知道现在二分图中已经没有增广路了,而且只存在两种边,第一种为两端都是已匹配点,第二种为一端已匹配、另一端未匹配。那么我们要找的最小点覆盖集肯定可以在所有的匹配点里找到,即对第一种边,随便挑一个点;对第二种边,挑匹配点。
那么我们怎么选这些匹配点呢?因为所有与未匹配点相连的点都应该是最小点覆盖集里的点,那么跟这些点匹配的点当然是不需要在最小点覆盖集里了。我们可以把二分图分成两部分,即左边和右边,我们可以使用匈牙利算法从未匹配点开始寻找增广路,对图中的点进行标记,最终左边未标记的点和右边标记了的点组成了最小点覆盖。
其实也可以分类讨论考虑最小点覆盖问题,即左边有未标记点和左边无未标记点。对于第一种情况,我直接左边的所有点组成的点集组成最小点覆盖;对于第二种情况,我们则是为了找到所有能覆盖未标记点所在的边而进行匈牙利的match操作,即我们发现最小点覆盖中不可能有这个点,于是就去找能够覆盖该点所有关联边的代替点集合。
最大点独立:
既然我们知道最小点覆盖,那么根据定理8,我们只需要求出最小点覆盖的补集就是最大点独立了,即标记了的左边点和未标记的右边点。
例题解析:
1、二分图最小点覆盖:
题目链接:UVA 11419
解题思路:
二分图最小点覆盖模板题。把每一行变成左边的点,每一列变成右边的点,这样就变成了最小点覆盖问题,可用上述算法解决。
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define maxn 1005 using namespace std; int n,m,K,a[maxn][maxn],vx[maxn],vy[maxn],prex[maxn],prey[maxn]; bool dfs(int index) { vx[index]=1; for(int i=1;i<=m;i++) { if(!vy[i]&&a[index][i]) { vy[i]=1; if(!prey[i] || dfs(prey[i])) { prey[i]=index; prex[index]=i; return 1; } } } return 0; } int hungary() { int ans=0; memset(prex,0,sizeof(prex)); memset(prey,0,sizeof(prey)); for(int i=1;i<=n;i++) { memset(vy,0,sizeof(vy)); if(dfs(i)) ans++; } return ans; } int solve() { printf("%d",hungary()); memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy)); for(int i=1;i<=n;i++) if(!prex[i]) dfs(i); for(int i=1;i<=n;i++) if(!vx[i]) printf(" r%d",i); for(int i=1;i<=m;i++) if(vy[i]) printf(" c%d",i); printf("\n"); } int main() { while(~scanf("%d %d %d",&n,&m,&K)&&n+m+K) { memset(a,0,sizeof(a)); int x,y; while(K--) { scanf("%d %d",&x,&y); a[x][y]=1; } solve(); } return 0; }
2、二分图最大点独立:
题目链接:UVALIVE 4288
解题思路:
二分图最大点独立,因为只需要求点独立数,所以直接套用匈牙利算法即可。构图方面,把所有人分成两类,喜欢猫的和喜欢狗的,形成二分图,并把所有存在矛盾关系的人连一条边,即讨厌对方喜欢的动物或者喜欢对方讨厌的动物。
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define maxn 505 using namespace std; int n,m,c,d,K,a[maxn][maxn],vy[maxn],prey[maxn]; int likec[maxn],liked[maxn],hatec[maxn],hated[maxn]; bool dfs(int index) { for(int i=1;i<=m;i++) { if(!vy[i]&&a[index][i]) { vy[i]=1; if(!prey[i] || dfs(prey[i])) { prey[i]=index; return 1; } } } return 0; } int hungary() { int ans=0; memset(prey,0,sizeof(prey)); for(int i=1;i<=n;i++) { memset(vy,0,sizeof(vy)); if(dfs(i)) ans++; } return ans; } int main() { int T; scanf("%d",&T); getchar(); while(T--) { n=m=0; scanf("%d %d %d",&c,&d,&K); getchar(); char ch1,ch2; int x,y; for(int i=1;i<=K;i++) { scanf("%c%d %c%d",&ch1,&x,&ch2,&y); if(ch1=='C') { n++; likec =x,hated =y; } else { m++; liked[m]=x,hatec[m]=y; } getchar(); } memset(a,0,sizeof(a)); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(likec[i]==hatec[j] || liked[j]==hated[i]) { a[i][j]=1; } } } int ans=hungary(); printf("%d\n",n+m-ans); } return 0; }
参考资料:
Matrix 67的博客
相关文章推荐
- 2015 三羊献瑞
- springmvc(1)
- 类与对象
- Linux上MySql源码安装(或升级)5.6.22
- HTTP消息中header头部信息的讲解
- iOS地图定位功能的实现(解决代理方法不执行问题,解决默认定位苹果总部问题)
- iOS UIScrollView 的基本用法
- 嵌入式C语言开发基础知识
- Java并发编程系列之十九:原子操作类
- 设计模式--策略模式
- 让别人舒服的程度决定你路的高度
- Android_为什么我要看这么多Android的书
- 理解JAVA里的所有参数传递都是值传递
- Android Studio调试功能使用总结
- JAVA多线程实现
- kthread
- JAVA学习之必备知识点琐碎(一)
- 第三章:表达式与运算符
- Python Twisted架构英文版
- 第四次作业:文件的复制速度