简单讲:
概念:
匹配:设G是一个图,若M中的边都是杆,并且任意两条边均不邻接,则称M为G的一个匹配。
最大匹配(边的最大独立集):G的边数最多的匹配称为最大匹配。
点的最大独立集:设S是图G的顶点子集合。如果S中任意两个顶点在G中均不邻接,则称S是G的一个点独立集
最小点覆盖:找出最少的点,使得每条边至少和其中一个点连接。
最小边覆盖: 找出最少的边,使得每个点都有边与其相连
二分匹配:最大匹配:hdu 2063、1498
最小路径覆盖:poj 2226、1422、4160
最大独立集:hdu 1068、3829
最小点覆盖:hdu 1150、3360
最优匹配:hdu 2255
二分图最优匹配:对于二分图的每条边都有一个权(非负),要求一种完备匹配方案,使得所有匹配边的权和最大,记做最优完备匹配。(特殊的,当所有边的权为1时,就是最大完备匹配问题)
先说一个定理:设M是一个带权完全二分图G的一个完备匹配,给每个顶点一个可行顶标(第i个x顶点的可行标用lx[i]表示,第j个y顶点的可行标用ly[j]表示),如果对所有的边(i,j) in G,都有lx[i]+ly[j]>=w[i,j]成立(w[i,j]表示边的权),且对所有的边(i,j) in M,都有lx[i]+ly[j]=w[i,j]成立,则M是图G的一个最优匹配。
Kuhn-Munkras算法(即KM算法)流程:
v (1)初始化可行顶标的值
v (2)用匈牙利算法寻找完备匹配
v (3)若未找到完备匹配则修改可行顶标的值
v (4)重复(2)(3)直到找到相等子图的完备匹配为止
KM算法主要就是控制怎样修改可行顶标的策略使得最终可以达到一个完美匹配,首先任意设置可行顶标(如每个X节点的可行顶标设为它出发的所有弧的最大权,Y节点的可行顶标设为0),然后在相等子图中寻找增广路,找到增广路就沿着增广路增广。而如果没有找到增广路呢,那么就考虑所有现在在匈牙利树中的X节点(记为S集合),所有现在在匈牙利树中的Y节点(记为T集合),考察所有一段在S集合,一段在not T集合中的弧,取 delta = min {l(xi)+l(yj)-w(xi,yj) , | xi in S, yj in not T} 。明显的,当我们把所有S集合中的l(xi)减少delta之后,一定会有至少一条属于(S, not T)的边进入相等子图,进而可以继续扩展匈牙利树,为了保证原来属于(S,T )的边不退出相等子图,把所有在T集合中的点的可行顶标增加delta。随后匈牙利树继续扩展,如果新加入匈牙利树的Y节点是未盖点,那么找到增广路,否则把该节点的对应的X匹配点加入匈牙利树继续尝试增广。
int n,sx[20],sy[20],lx[20],ly[20],match[20],w[20][20]; int dfs(int k) { int i; sx[k]=1; for(i=1;i<=n;i++) { if(!sy[i]&&w[k][i]==(lx[k]+ly[i])) { sy[i]=1; if(!match[i]||dfs(match[i])) { match[i]=k; return 1; } } } return 0; } void KM() { int i,j,k,min; memset(ly,0,sizeof(ly)); for(i=1;i<=n;i++) { lx[i]=w[i][1]; for(j=2;j<=n;j++) { if(lx[i]<w[i][j]) lx[i]=w[i][j]; } } memset(match,0,sizeof(match)); for(i=1;i<=n;i++) { while(1) { memset(sx,0,sizeof(sx)); memset(sy,0,sizeof(sy)); if(dfs(i))break; min=1000000000; for(j=1;j<=n;j++) { if(sx[j]) { for(k=1;k<=n;k++) if(!sy[k]) min=min<(lx[j]+ly[k]-w[j][k])?min:(lx[j]+ly[k]-w[j][k]); } } for(j=1;j<=n;j++) { if(sx[j])lx[j]-=min; if(sy[j])ly[j]+=min; } } } }
/*****************************************************************************************************************************/
二分图相关问题
二分图最大匹配
二分图最小覆盖
二分图最大独立集
二分图最小路径覆盖
二分图最优匹配
稳定婚姻问题
二分图定义及判定
定义:二分图中,顶点可以分为两个集合X和Y,每一条边的两个顶点都分别位于X和Y集合中
判定:利用BFS或者DFS进行黑白染色,共享一边的两点异色,检查是否存在矛盾
图G为二分图的充要条件是图中不含奇环
证明相当繁琐,具体参见组合数学
Why?
如果是V0或V2或…..的匹配的改变导致找到交错路,那么改变的这点也存在于交错路中,那么在改变之前就应该找到交错路
DFS实现 int find(int k) { for (每个与k相邻的点j) if (cover[j] == FALSE) { q = link[j]; link[j] = k; cover[j] = TRUE; if (q == -1 || find(q) == 1) return 1; link[j] = q; } return 0; } work() { link[ ]数组初始化为-1 for (i = 0 ; i < m ; i++) { cover[ ]数组初始化为FALSE; find(i); } }
二分图最小覆盖
求得最大匹配M后,图中已经不存在交错路。从右边未匹配的点开始,以寻找交错路的方式扩展节点,并标记路过的节点。取右边未标记的节点,左边标记的节点,则构成一组最小覆盖。
1,所取节点数=|M| .右边未匹配的点肯定被标记了,左边未匹配的点不可能被标记(否则找到了交错路),一条匹配边的左端点被标记,那么右端点也肯定被标记,所以所取节点恰覆盖一条匹配边
ƒ3,最小(why?)
二分图最大独立集
一个n*n的棋盘上,有一些单位小方格不能放置骑士。求出最多可以放置几个相互不攻击的骑士
二分图的最小路径覆盖
每个球看做是一个节点,对于球a,b(a<b),如果a+b是完全平方数,那么有一条a指向b的边,由于a总是小于b,显然所建图无环。
每根柱子相当于一条路径,而且每个球只能位于一根柱子上,所以保证了路径不会相交,至此,问题转化为最小路径覆盖
根据答案的单调性,我们可以通过二分答案解,将每次二分出的答案和N做比较,最后得出答案
二分图最优匹配
设顶点Xi的顶标为a[i],顶点Yi的顶标为b[i]
丘比特选择了一组数目相等的男女,感应到他们互相之间的缘分大小,射出神箭,使他们相爱。请帮助丘比特选择最好的方法,使得每个人被射中一次,且被射中的每一对情侣的缘分总和最大。
分析
稳定婚姻
初始每位女士处于未匹配状态。
当存在未匹配女士时
该女士在所有未拒绝过她的男士中选择她最喜欢的男士作为配偶
‚男士在所有选择他的女士中选择他最喜欢的作为配偶