1.定义
可以把图中的点分成两部分,使得每部分内部两两点之间没有连边。
2.二分图判定
没有奇环的图,或者能够黑白染色的图。
3.一些东西:
①匹配
边的子集,两两边没有公共点。
②覆盖
点的子集使得每条边至少和一个点关联
③支配集
点的子集,使得每个点要么自己在集合里,要么和一个集合里的点关联。
④独立集
点的集合,使得任意点之间没有连边
4.完美匹配
①定义:最大匹配中的每个点都是匹配点
②Hall定理(完美匹配的充分必要条件)
选择任意的左部点S个,把所有这S个点关联的K个右部点取出来,一定有|S|<=|K|
证明:
必要性:有完美匹配的二分图必然满足Hall定理。假设存在S>K,那么这S个点不可能都被选上。
充分性:假设二分图满足Hall定理,但是最大匹配不是完美匹配。
所以,能找到一个左部点的非配点a1,开始Hungary。由于Hall定理,非匹配点一定有连边。右部点b1一定是匹配点。否则有增广路。
然后访问右部点b1的左部匹配点a2,a2一定还有另外的一个关联的点b2。这个点一定是非匹配点,否则就从a1到b2有一条增广路。
b2又有一个左部匹配点a3.。。。。。。
发现,点数会无限增长下去。
例题:
也是一个多重匹配的推广
Hall定理的好处是,我们可以通过另外一种方法考虑有没有完美匹配。并不一定要建图跑二分图了
考虑指向右部点的总点数大于∑ai,也就意味着任意一个右部点的区间[p,q]完全包含的所有[li,ri]区间的ai和和不能大于[p,q]的长度p-q+1
任意,只用考虑[lj,ri]的区间,按照右端点排序,不断枚举右端点,线段树维护所有左端点到当前r的s+li-1值,前缀加,前缀求max
5.Konig定理
最小点覆盖=最大匹配
证明:由于匹配边没有公共点,所以最小点覆盖的下界是最大匹配。
我们只需要证明存在一种构造方法使得达到下界。
完成最大匹配后,从每个左部非匹配点找增广路(一定会失败),把所有访问过得左部点和右部点打上标记。
左部非标记点和右部标记点构成了最小点覆盖
因为:
1.每个左部非匹配点都被打上了标记。
2.每个右部非匹配点都没有打上标记。否则找到一条增广路。
3.每对匹配点要么都打上标记,要么都没有。因为访问过其中一个点,必然能通过pre找到另一个点。
所以,其实是每个匹配边选择一个点。和最大匹配相等。
再证是覆盖:
1.每个匹配边被覆盖。
2.左非匹配,右匹配。从这个左部非匹配点出发,一定会标记右部这个匹配点。
3.左匹配,右非匹配。这个左部点一定没有打上标记,否则会找到这个右部非匹配点找到增广路。
4.不存在两边都是非匹配点。否则本身就有增广路。
证毕。
最大独立集=N-最小点覆盖
证明:最大独立集下界是这个。因为一定存在构造方法:即把所有最小点覆盖抠掉。
上界也是这个。否则要把一个覆盖点加入独立集。如果还是独立集的话,那么最小点覆盖就可以更小。矛盾。
证毕。
6.最小链覆盖(DAG中)
点不能相交:拆点。把原图中原来的边(u,v),从u+连到v-。然后最小链覆盖就是原图点数-最大匹配。
证明:开始每个点都是一个链,每合并两个点(二分图中找一条匹配边),就可以减少一。而且,匹配本身不能有公共点,符合点不能相交
点可以相交:拆点。传递闭包。能到达的点二分图上连边。然后转化成点不能相交。
证明:可以相交就是对于类似叉号的图有帮助。然后我们就好似建了一座天桥,可以直接到达,不用经过交叉点。
最小链覆盖的方案求法:
把二分图的匹配边还原一下即可。
upda:2019.5.11
其实不用传递闭包,毕竟是DAG,直接反向topo,向所有后继连边即可。O(n^2)
7.Dilworth定理和最长反链
最长反链:其实是一个点的集合。集合中两两之间不可达。
最长反链=最小链覆盖。证明不会。
构造最长反链:
求最小链覆盖。从那个二分图匹配中,找最大独立集,选择(u+,u-)都在独立集的u,就是最长反链。
证明不会。
例题:
就好比最大匹配和最小点覆盖、最小点覆盖和最大独立集、最大流和最小割的关系。
都是对偶问题,哪个更好做,更符合题意建模,就做哪一个。
导弹拦截第二问。可以看做DAG。最小不下降子序列覆盖=最长上升子序列长度。因为这个就是反链。两两不可达。
[CTSC2008]祭祀
第三问要找能在最长反链中的。枚举点,抠掉这个点的所有出点和入点,新图找最长反链len。
如果len=ans-1,那么把这个点加回去,最大独立集肯定可以+1,那么就是可行的点。
由于最长反链是ans,所以不存在去掉之后len大于等于ans的情况(什么证明啊这是)。
[TJOI2015]组合数学
网格图是DAG,求最小链覆盖,每个点要重复多次覆盖。没法做。
Dilworh定理合理外推可以得到:就是带权最大反链
最大反链这里就是右上-左下的一些点。f[i][j]递推即可
#include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define mk(a,b) make_pair(a,b) #define numb (ch^'0') using namespace std; typedef long long ll; template<class T>il void rd(T &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');} template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');} template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar(' ');} namespace Miracle{ const int N=1005; ll f[N][N],a[N][N]; int n,m; int t; int main(){ int t; rd(t); while(t--) { rd(n);rd(m); memset(f,0,sizeof f); for(reg i=1;i<=n;++i){ for(reg j=1;j<=m;++j){ rd(a[i][j]); } } ll ans=0; for(reg i=1;i<=n;++i){ for(reg j=m;j>=1;--j){ f[i][j]=max(f[i-1][j],max(f[i][j+1],f[i-1][j+1]+a[i][j])); ans=max(ans,f[i][j]); } } printf("%lld ",ans); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/3/31 17:05:23 */
upda:2018.11.5
9.有完备匹配的二分图可行边和必须边
与最大匹配有关。
给边定向。
匹配边右-左
非匹配边左-右
Tarjan判SCC
对于边(x,y)
如果c[x]==c[y]那么(x,y)是可行边。
如果(x,y)是匹配边,并且c[x]!=c[y]那么(x,y)是必须边