2023.7.20 二分图匹配

前置知识

  • 匈牙利算法求二分图最大匹配
bool dfs(int x) {
	for (int i = head[x]; i; i = nxt[i]) {
		int y = to[i];
		if (!vis[y]) {
			vis[y] = 1;
			if (!match[y] || dfs(match[y])) {
				match[y] = x;
				return 1;
			}
		}
	}
	return 0;
}

for (int i = 1; i <= n; ++i) {
	memset(vis, 0, sizeof vis);
	if (dfs(i)) ++ans;
}

其实很好理解 就是我们枚举左边的点 然后尝试找到右边的点与其匹配
如果右边的这个点还没被匹配 那么直接匹配
否则 看一下右边这个点当前匹配的这个能不能匹配别的点 然后把它空出来给它匹配

这个复杂度是 \(O(VE)\) 的 其中 \(V\) 代表左边的点数 \(E\) 代表二分图中的边数
如果大概都算一个数量级的话就是 \(O(n^3)\)

  • 霍尔海雅定理及其推论

定理内容:如果这个二分图所有左边的点都能匹配上右边的点 当且仅当从左边任意选出 \(k\) 个点 他们连接的右边的点的数量 \(\ge k\)

这个非常一眼 重要的是它的推论

如果有 \(n\) 个左边的点 那么最大匹配数为 \(n - a\) 当且仅当从左边任意选出 \(k\) 个点 他们连接右边点的数量 \(\ge k - a\)

如果一眼了霍尔定理 实际这个推论也很一眼
真正重要的东西来了:

\(tr(S')\) 表示集合 \(S'\) 中的左端点可以连向的右端点点集
那么一个二分图的最大匹配为 \(|S| - max_{S' \subseteq S}(|S'| - |tr(S')|)\)

其实有了上面的铺垫看这个式子也挺好理解 但是这个式子在某些题非常重要


T1 [NOI Online #1 提高组] 序列

luogu link

感觉不是很美妙的一道题

首先观察操作的性质 发现操作2不会改变两数之和 所以我们如果按操作2连边 那么只需要保证这个联通块内部 \(a\) 的和等于 \(b\) 的和即可

然后看操作1 如果我们把操作1也连一条边
那么如果图是一个二分图 那么左右两端的差不变 判断差值即可
否则如果是一坨的话 那么每次操作就相当于让总和两个两个加或减
所以此时判断 \(a\)\(b\) 总和的差值的奇偶性


T2 Maximize Mex

luogu link

首先第一眼考虑倒着做
然后这个用二分图匹配来求 \(mex\) 的最大值很有启发性

我们对于每个学生 把他的社团编号和能力值连一条边
那么跑二分图匹配即可

但是由于跑一次是 \(O(n ^ 3)\) 的 如果正着做就是 \(O(n ^ 4)\)
如果倒着做 可以发现多一个人的情况显然比少一个人不劣
所以如果倒着做 从上次失配的 \(mex\) 重新匹配即可
这样复杂度就降到了 \(O(n ^ 3)\)


T3 「2017 山东一轮集训 Day2」Pair

link

因为两个数组匹配的时候都是可以打乱顺序的 所以我们想到对其中一个数组排序 先让一维有序

显然对 \(b\) 排序是好一点的 因为你要枚举 \(a\) 的区间

然后不难发现 对于一个位置 \(b\) 数组中该数越大 那么对于 \(a\) 中需要匹配的数的要求就越不严
那么显然每个 \(a\) 能匹配的数就是 \(b\) 的一段后缀


T4 「JOISC 2022 Day3」蚂蚁与方糖

link

posted @ 2023-08-05 21:58  Steven24  阅读(15)  评论(0)    收藏  举报