学习Hall’s Marriage Theorem
Posted cly-none
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习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 imes 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
",ans);
return 0;
}
小结:学了一个没卵用的定理。也挺好奇还有哪些二分图能用到这个定理。
以上是关于学习Hall’s Marriage Theorem的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 981F. Round Marriage