zoukankan      html  css  js  c++  java
  • [算法] 二分图最大匹配

    前言

    具体什么是二分图,如何判定,可以参考我的这篇博客

    定义

    简单来说,就是二分图中有满足任意两条边没有相同的点的边的集合,称为一组匹配,而边数最多的一组匹配称为该二分图的最大匹配。在一组匹配中,属于这组边的称为匹配边,不属于的称为非匹配边,属于这组匹配的点称为匹配点,不属于的称为非匹配点。

    匈牙利算法

    又称增广路算法。

    对于一组匹配 (M) ,若存在一条路径连接两个非匹配点,且使得匹配边与非匹配边交替出现,则称这条路径为增广路。

    在这里插入图片描述
    如上图,已匹配的边为红色,未匹配的边为绿色,则可以找到一组增广路 (8) ~ (2) ~ (7) ~ (4) 。不难发现增广路具有以下特点:

    • 以非匹配边开始,在以非匹配边结尾,那么长度必为奇数。
    • 路径上第一条边因为第一个点为奇数,则该路径上的第一个点为非匹配边,按照匹配边与非匹配边交替出现的性质可以得出,该路径的第奇数条边必为非匹配边,已经匹配的边必为第偶数条边,则有非匹配边的边数比匹配边的边数多一。
    • 最大匹配中不会有增广路。证明:假设最大匹配中存在增广路,则可以将增广路中的所有边的状态取反(即把非匹配边转换为匹配边,将匹配边转换为非匹配边),得到另一组匹配,而这组匹配的匹配边肯定会比之前的一组匹配的边数多一,则之前的这组匹配就不是最大匹配,与假设矛盾,证毕。

    在一张二分图中,若最大匹配为 (S) ,当且仅当 (S) 中不存在增广路。其确性基于 (hall) 定理,比较复杂就不在详讲,主要讲找二分图最大匹配的方法。

    大体思想就是枚举左部点,找到增广路后将这条路上的所有边的状态取反,得到边数更大的一组匹配。

    在匹配过程中,有两种情况会改变当前左部点 (u) 的匹配情况。

    1. 与之对应的右部点 (v) 是非匹配点,则可以将其的连边变为匹配边。
    2. 与之对应的右部点 (v) 是匹配点,但与 (v) 已经匹配的点 (u') 可以找到另一个未匹配的右部点 (v') ,则 (u) ~ (v) ~ (u') ~ (v') 为一条增广路,则将其状态取反。 (u) 对应的点 (v) 已经对 (u') 进行了标记,遍历 (u') 的时候就不会再遍历 (v) 了,看再次匹配 (u') 是否能找到上述的 (v') ,若找到 (v') ,意味着找到了增广路。

    最小点覆盖于最大匹配的关系

    (Konig) 定理可知:最小点覆盖的点数与最大匹配的边数相等

    证明较为复杂不详讲。

    C++实现

    int twin[MAXN];//右部节点与之匹配的左部节点
    bool vis[MAXN];//记录当前点是否走过
    bool Hungary(int now) {
    	int SIZ = v[now].size();
    	for(int i = 0; i < SIZ; i++) {
    		int next = v[now][i];
    		if(!vis[next]) {
    			vis[next] = true;
    			if(!twin[next] || Hungary(twin[next])) {//分别对应情况一与情况二
    				twin[next] = now;
    				return true;//匹配成功
    			}
    		}
    	}
    	return false;//匹配失败
    }
    int Match() {
    	int res = 0;
    	for(int i = 1; i <= n; i++) {
    		memset(vis, 0, sizeof(vis));
    		if(Hungary(i))
    			res++;
    	}
    	return res;
    }
    

    看看自己做对没有吖

  • 相关阅读:
    Spring@Profile注解
    day 32 子进程的开启 及其用法
    day 31 udp 协议SOCK_DGRAM
    day 30 客户端获取cmd 命令的步骤
    day 29 socket 理论
    day 29 socket 初级版
    有关 组合 继承
    day 27 多态 接口 类方法 静态方法 hashlib 摘要算法模块
    新式类和经典类的区别
    day 28 hasattr getattr serattr delattr 和带__内置__ 类的内置方法
  • 原文地址:https://www.cnblogs.com/C202202chenkelin/p/14070458.html
Copyright © 2011-2022 走看看