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 提高组] 序列
感觉不是很美妙的一道题
首先观察操作的性质 发现操作2不会改变两数之和 所以我们如果按操作2连边 那么只需要保证这个联通块内部 \(a\) 的和等于 \(b\) 的和即可
然后看操作1 如果我们把操作1也连一条边
那么如果图是一个二分图 那么左右两端的差不变 判断差值即可
否则如果是一坨的话 那么每次操作就相当于让总和两个两个加或减
所以此时判断 \(a\) 和 \(b\) 总和的差值的奇偶性
T2 Maximize Mex
首先第一眼考虑倒着做
然后这个用二分图匹配来求 \(mex\) 的最大值很有启发性
我们对于每个学生 把他的社团编号和能力值连一条边
那么跑二分图匹配即可
但是由于跑一次是 \(O(n ^ 3)\) 的 如果正着做就是 \(O(n ^ 4)\)
如果倒着做 可以发现多一个人的情况显然比少一个人不劣
所以如果倒着做 从上次失配的 \(mex\) 重新匹配即可
这样复杂度就降到了 \(O(n ^ 3)\)
T3 「2017 山东一轮集训 Day2」Pair
因为两个数组匹配的时候都是可以打乱顺序的 所以我们想到对其中一个数组排序 先让一维有序
显然对 \(b\) 排序是好一点的 因为你要枚举 \(a\) 的区间
然后不难发现 对于一个位置 \(b\) 数组中该数越大 那么对于 \(a\) 中需要匹配的数的要求就越不严
那么显然每个 \(a\) 能匹配的数就是 \(b\) 的一段后缀

浙公网安备 33010602011771号