时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

上一回我们已经将所有有问题的相亲情况表剔除了,那么接下来要做的就是安排相亲了。因为过年时间并不是很长,所以姑姑希望能够尽可能在一天安排比较多的相亲。由于一个人同一天只能和一个人相亲,所以要从当前的相亲情况表里选择尽可能多的组合,且每个人不会出现两次。不知道有没有什么好办法,对于当前给定的相亲情况表,能够算出最多能同时安排多少组相亲呢?

同样的,我们先将给定的情况表转换成图G=(V,E)。在上一回中我们已经知道这个图可以被染成黑白两色。不妨将所有表示女性的节点记为点集A,表示男性的节点记为点集B。则有A∪B=V。由问题可知所有边e的两个端点分别属于AB两个集合。则可以表示成如下的图:

同样的,我们将所有的边分为两个集合。集合S和集合M,同样有S∪M=E。边集S表示在这一轮相亲会中将要进行的相亲,边集M表示在不在这一次进行。对于任意边(u,v) ∈ S,我们称u和v为一组匹配,它们之间相互匹配。在图G,我们将边集S用实线表示,边集M用虚线表示。得到下图:

则原问题转化为,最多能选择多少条边到集合S,使得S集合中任何两条边不相邻(即有共同的顶点)。显然的,|S|<=Min{|A|, |B|}。

那么能不能找到一个算法,使得能够很容易计算出尽可能多的边能够放入集合S?我们不妨来看一个例子:

对于已经匹配的点我们先不考虑,我们从未匹配的点来做。这里我们选择A集合中尚未匹配的点(A3和A4)考虑:

对于A3点,我们可以发现A3与B4右边相连,且都未匹配。则直接将(A3,B4)边加入集合S即可。

对于A4点,我们发现和A4相连的B3,B4点都已经匹配了。但是再观察可以发现,如果我们将A2和B2相连,则可以将B3点空出来。那么就可以同时将(A2,B2),(A4,B3)相连。将原来的一个匹配变成了两个匹配。

让我们来仔细看看这一步:我们将这次变换中相关联的边标记出来,如下图所示紫色的3条边(A2,B2),(A2,B3),(A4,B3)。

这三条边构成了一条路径,可以发现这条路径有个非常特殊的性质。虚线和实线相互交错,并且起点和终点都是尚未匹配的点,且属于两个不同的集合。我们称这样的路径为交错路径。

再进一步分析,对于任意一条交错路径,虚线的数量一定比实线的数量多1。我们将虚线和实线交换一下,就变成了下面的图:

在原来1个匹配的基础上,我们得到了2个新的匹配,S集合边的数量也增加了1。并且原来在已经匹配的点仍然是已经匹配的状态。

再回头看看A3点匹配时的情况:对于(A3,B4)这一条路径,同样满足了交错路径的性质。

至此我们得到了一个找新匹配的有效算法:

选取一个未匹配的点,查找是否存在一条以它为起点的交错路径。若存在,将该交错路径的边虚实交换。否则在当前的情况下,该点找不到可以匹配的点。

又有对于已经匹配的点,该算法并不会改变一个点的匹配状态。所以当我们对所有未匹配的点都计算过后,仍然没有交错路径,则不可能找到更多的匹配。此时S集合中的边数即为最大边数,我们称为最大匹配数。

那么我们再一次梳理整个算法:

1. 依次枚举每一个点i; 
2. 若点i尚未匹配,则以此点为起点查询一次交错路径。

最后即可得到最大匹配数。

在这个基础上仍然有两个可以优化的地方:

1.对于点的枚举:当我们枚举了所有A中的点后,无需再枚举B中的点,就已经得到了最大匹配。
2.在查询交错路径的过程中,有可能出现Ai与Bj直接相连,其中Bj为已经匹配的点,且Bj之后找不到交错路径。之后又通过Ai查找到了一条交错路径{Ai,Bx,Ay,…,Az,Bj}延伸到Bj。由于之前已经计算过Bj没有交错路径,若此时再计算一次就有了额外的冗余。所以我们需要枚举每个Ai时记录B集合中的点是否已经查询过,起点不同时需要清空记录。

伪代码

输入

第1行:2个正整数,N,M(N表示点数 2≤N≤1,000,M表示边数1≤M≤5,000)
第2..M+1行:每行两个整数u,v,表示一条无向边(u,v)

输出

第1行:1个整数,表示最大匹配数

样例输入

5 4
3 2
1 3
5 4
1 5
样例输出

2

题解:最大匹配的做法就是找一个集合到另外一个集合的最多边数,但是要满足一一对应,一个点最多只能有一条边

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>using namespace std;vector<int> vec[10004];
int pre[10004];
bool visited[10004];bool find(int x)
{for(int i = 0;i < vec[x].size();i++)   //从每一个邻接点找增广路径 {int k = vec[x][i];if(!visited[k])                  {visited[k] = true;if(0 == pre[k] || find(pre[k])) //找到一条 {pre[k] = x;                 //取反,路径多了一条 return true;}}}return false;                         //所有邻接点找完都没有找到增广路径
}int main()
{int n,m;cin>>n>>m;int u,v;int ans = 0;for(int i = 0;i < m;i++){scanf("%d%d",&u,&v);vec[u].push_back(v);vec[v].push_back(u);}memset(pre,0,sizeof(pre));         //表示这是一条增广路径 for(int i = 1;i <= n;i++){memset(visited,false,sizeof(visited));if(find(i))                  //找到一条增广路径 {ans++;}}cout<<ans / 2<<endl;           //从男到女找了一次,从女到男又找了一次,多了一次 return 0;} 

#1122 : 二分图二•二分图最大匹配之匈牙利算法相关推荐

  1. 二分图的最大匹配(匈牙利算法)HDU1083

    二分图: 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同 ...

  2. hihocoder 1122 : 二分图二•二分图最大匹配之匈牙利算法

    首先,匈牙利算法是用来求二分图的最大匹配的,它的核心问题就是找增广路径.匈牙利算法的时间复杂度为O(VE),其中 V为二分图左边的顶点数,E为二分图中边的数目. 现在我们来看看增广路有哪些性质: (1 ...

  3. 51nod 2006 飞行员配对(二分图最大匹配) 裸匈牙利算法 求二分图最大匹配题

    题目: 题目已经说了是最大二分匹配题, 查了一下最大二分匹配题有两种解法, 匈牙利算法和网络流. 看了一下觉得匈牙利算法更好理解, 然后我照着小红书模板打了一遍就过了. 匈牙利算法:先试着把没用过的左 ...

  4. python最长匹配_二分图最大匹配:匈牙利算法的python实现

    二分图匹配是很常见的算法问题,一般用匈牙利算法解决二分图最大匹配问题,但是目前网上绝大多数都是C/C++实现版本,没有python版本,于是就用python实现了一下深度优先的匈牙利算法,本文使用的是 ...

  5. P3386 【模板】二分图最大匹配(匈牙利算法模板)

    题目链接:点击这里 题目大意: 给定一个二分图,其左部点的个数为 nnn ,右部点的个数为 mmm ,边数为 eee ,求其最大匹配的边数. 题目分析: 本题使用的匈牙利算法完成的二分图最大匹配 具体 ...

  6. 51Nod-2006 飞行员配对(二分图最大匹配,匈牙利算法)

    2006 飞行员配对(二分图最大匹配) 题目来源: 网络流24题 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 第二次世界大战时期,英国皇家空军从沦陷国征募 ...

  7. 二分图最大匹配(匈牙利算法)

    二分图的匹配:给定一个二分图G,在G中的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配. 二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其 ...

  8. 二分图最大匹配(匈牙利算法,Dinic网络流算法)

    二分图最大匹配 二分图最大匹配问题: 有两个集合A,B,两个集合间有多条边连接集合中的点,且单个集合中的点各不相连,求两集合的点能两两配对的最大匹配数. (参考:)二分图最大匹配--匈牙利算法 匈牙利 ...

  9. 二分图的最大匹配:匈牙利算法,先到先得,能让则让,男生找妹子

    原题链接:https://www.acwing.com/problem/content/description/863/ 左边站了一排男的,右边占了一排女的. 左边的某些男的,对右边的某些女的有好感. ...

  10. 图论二分图问题讲解-染色法和匈牙利算法

    二分图 概述: 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两 ...

最新文章

  1. python使用matplotlib可视化线图(line plot)、并自定义设置可视化图像中没有网格线(remove grid line in matplotlib plot result)
  2. 【Flutter】Flutter 混合开发 ( Flutter 与 Native 通信 | Android 端实现 BasicMessageChannel 通信 )
  3. 子div在父div中置底
  4. Shell 脚本知识回顾 (五) —— Shell 循环
  5. php 纯文本输出_关于PHP的语法介绍,新手必看
  6. css中英文混排 标点,浅析css中英文混排时行高不一样的原因及其解决方法
  7. GaiGai----1
  8. TCP、UDP、HTTP
  9. 电脑黑屏但光标、杀毒软件加速球可见
  10. php 0 加减乘除,php 加减乘除计算器 用php简单实现加减乘除计算器
  11. JS格式化中国标准时间
  12. Revit二次开发 ----> 管道翻弯
  13. 内核态的文件操作函数:filp_open、filp_close、vfs_read、vfs_write、set_fs、get_fs
  14. 利用群发短信进行精准高效的会员营销
  15. [书蕴笔记-2]使用word2vec模型迭代获取标签
  16. HASH和HMAC(7):SHA3-224/256/384/512算法原理
  17. idea中使用git相关操作说明
  18. 第7篇:MS12-020蓝屏漏洞在实战中的巧用
  19. node.js下安装 webpack 的时候,出现:TypeError:this is not a typed array;
  20. Nofollow涵义

热门文章

  1. 微信小程序点播插件_小程序直播插件接入 - 微信小程序
  2. 如何使用maven工具引入人大金仓驱动?
  3. jQuery实现好评点亮星星
  4. C++函数重载和重写
  5. 区域间人口流动所引起的教育投资收益错位问题
  6. vue h5页面获取手机设备信息
  7. 象棋人工智能算法的C++实现(一)
  8. 第8章 生成式深度学习
  9. SAECCE 2021展位预定已过半,观众预登记系统上线啦!
  10. 将libcef_dll_wrapper嵌入自建独立工程