【学习】Hall’s Marriage Theorem
其实是在做题时遇到这个定理的。
这个定理的图论意义是:
对于一个二分图\(G=\{X+Y,E\}\),它满足:
\(\forall W \subseteq X, \, |W| \leq |N_G(W)|\) \(\iff\)\(X\)中的每个结点都有匹配.
其中\(N_G(W)\)为图\(G\)中所有与\(W\)相连的结点的集合。
必要性显然。
对于充分性,不会……以后再补充。
由这个定理,我们能得到一个推论:
二分图\(G\)的最大匹配\(M\)等于\(|X| - \max (|W| - |N_G(W)|)\).
顺便一提,我们允许\(W = \emptyset\),故\(\max (|W| - |N_G(W)|) \geq 0\)。
我们分两步来证明这个推论。在此,我们假设\(W_0 \subseteq X\)满足\(|W_0| - |N_G(W_0)| = \max (|W| - |N_G(W)|)\)
- 证明:\(M \leq |X| - \max (|W| - |N_G(W)|)\).
考虑\(W_0\),即使\(N_G(W_0)\)中的每个结点都与\(W_0\)中的结点匹配,也会有\(|W_0| - |N_G(W_0)|\)个结点得不到匹配。故\(X\)中至少有\(|W_0| - |N_G(W_0)|\)个结点得不到匹配。因此,\(M \leq |X| - \max (|W|)\)。 - 证明:\(M \geq |X| - \max (|W| - |N_G(W)|)\).
我们在\(Y\)中添加\(\max (|W| - |N_G(W)|\)个结点与\(X\)中所有结点相连得到新图\(G`\),那么,\(|W_0| - |N_{G`}(W_0)| = 0\)。由Hall‘s Marriage Theorem可知,图\(G`\)中\(X\)的每个元素都有匹配。而对于\(W_0\),因为\(|W_0| = |N_{G`}(W_0)|\),所以\(N_{G`}(W_0)\)中的每个元素都与\(W_0\)中的元素匹配,可得我们新加入的结点都有匹配。因此,除\(W_0\)中有\(|W_0|-|N_G(W_0)|\)个结点与新加入的结点匹配之外,\(X\)中其余结点都与原来\(Y\)中的结点匹配。故在删去新加的结点后,\(X\)中至多有\(|W_0| - |N_G(W_0)|\)个结点没有匹配。则\(M \geq |X| - \max (|W| - |N_G(W)|)\)。
那么,这个定理及其推论有什么用呢?因为要枚举\(X\)的所有子集,所以一般是没什么用的。然而,某些有特殊性质的二分图的最大匹配问题,会使用这个定理及其推论来转化问题。
例题
arc076F Exhausted?
题意:给出二分图\(G=\{X+Y,E\}\),\(X\)中的所有结点满足:若其编号为\(i\),则只与\(Y\)中编号小于等于\(L_i\)或编号大于等于\(R_i\)的结点连边。给出\(|X|,|Y|\)和所有的\(L_i,R_i\),求\(G\)的最大匹配\(M\)。(输出\(|X|-M\))
\(|X|,|Y| \leq 2 \times 10^5\).
有了这个定理,问题就简单了。我们只要求\(\max (|W| - |N_G(W)|)\)。对于\(W \subseteq X\),\(N_G(W)\)就是形如\(Y - [l,r]\)的形式,其中\([l,r]\)是\(Y\)中一个编号的区间。我们枚举\(r\),用线段树实现区间加和区间查最大值即可。具体做法不再阐述。
时间复杂度\(O(n \log n)\)。
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
int n,m,ans,cnt;
struct data {
int l,r;
} ordl[N],ordr[N];
bool cmpl(data a,data b) {
return a.l < b.l;
}
bool cmpr(data a,data b) {
return a.r < b.r;
}
struct node {
int mx,tag;
} t[N << 2];
void puttag(int x,int val) {
t[x].mx += val;
t[x].tag += val;
}
void push_down(int x) {
puttag(x<<1,t[x].tag);
puttag(x<<1|1,t[x].tag);
t[x].tag = 0;
}
void push_up(int x) {
t[x].mx = max(t[x<<1].mx,t[x<<1|1].mx);
}
void modify(int l,int r,int val,int x=1,int lp=1,int rp=m) {
if (l > rp || r < lp) return;
if (lp >= l && rp <= r) {
puttag(x,val);
return;
}
if (t[x].tag) push_down(x);
int mid = (lp + rp) >> 1;
modify(l,r,val,x<<1,lp,mid);
modify(l,r,val,x<<1|1,mid+1,rp);
push_up(x);
}
int query(int l,int r,int x=1,int lp=1,int rp=m) {
if (l > rp || r < lp) return 0;
if (lp >= l && rp <= r) return t[x].mx;
if (t[x].tag) push_down(x);
int mid = (lp + rp) >> 1;
return max(query(l,r,x<<1,lp,mid),query(l,r,x<<1|1,mid+1,rp));
}
int main() {
int a,b;
scanf("%d%d",&n,&m);
ans = max(0,n - m);
cnt = n;
for (int i = 1 ; i <= cnt ; ++ i) {
scanf("%d%d",&a,&b);
a ++;
b --;
if (a > b) {
i --, cnt --;
continue;
}
ordl[i] = (data) {a,b};
ordr[i] = (data) {a,b};
}
sort(ordl+1,ordl+cnt+1,cmpl);
sort(ordr+1,ordr+cnt+1,cmpr);
int pl = 1, pr = 1;
for (int i = 1 ; i <= m ; ++ i) {
modify(1,i,1);
for (; ordl[pl].l <= i && pl <= cnt ; ++ pl)
modify(ordl[pl].l,m,1);
ans = max(ans,query(1,i) - m);
for (; ordr[pr].r <= i && pr <= cnt ; ++ pr)
modify(ordr[pr].l,m,-1);
}
printf("%d\n",ans);
return 0;
}
小结:学了一个没卵用的定理。也挺好奇还有哪些二分图能用到这个定理。
upd 2018.12.26
假如\(G\)满足,\(X\)中的每一个结点与\(Y\)中一个区间内的结点连边,即\(\forall a \in X, N_G(a) = [l_a,r_a]\)。
定义对于\(Y\)中的一个编号区间\([l,r]\),\(f([l,r])\)为\(X\)中只与\([l,r]\)中点连边的点构成的集合,即\(\{ a \in X \ | \ N_G(a) \subseteq [l,r] \}\)。
求证:
证明:
- 必要性。令\(W = f([l,r])\),那显然有\(N_G(W) \subseteq [l,r]\)。因此,\(|f([l,r])| = |W| \leq |N_G(W)| \leq |[l,r]|\)。
- 充分性。考虑任意一个\(W \subseteq X\),那么\(N_G(W)= \bigcup_{a \in W} [l_a,r_a]\)。那么,\(N_G(W)\)就一定可以被表示为若干个互不相交的区间的并。因为每个\(X\)中的结点都只和一个区间内的点连边,所以我们可以把\(W\)划分为若干个集合,其中每个集合对应\(N_G(W)\)中的一段区间。对于我们划分出来的任意一个集合,假如它对应的区间为\([l,r]\),那这个集合就一定是\(f([l,r])\)的子集。因此,对于\(W\)划分出来的每一集合\(S\)都满足\(|S| \leq |N_G(S)|\),故\(W\)也满足\(|W| \leq |N_G(W)|\)。