KM Algorithm

交错树


如果从某个左部节点出发寻找增广路失败,那么在dfs的时候,所有经过的节点和边,共同构成一棵交错树

 

顶标


给左部节点一个整数值Ai,右部节点一个整数值Bj,满足Ai+Bj>=w(i,j)  初始时Ai=max{ w(i,j) } , Bj=0

 

相等子图


二分图中所有节点和满足Ai+Bj=w(i,j)的边构成子图

 

定理 若相等子图中存在完备匹配,该匹配即为二分图最大带权匹配


  1. 一个匹配失败的左部节点形成一个交错树T
  2. 右部节点通过匹配边访问左部节点
  3. 左部节点通过非匹配边访问右部节点
  4. 为了让该失配节点成功匹配,需要增加匹数
  5. 由于右部节点访问到的点是固定的,所以只能通过左部节点增加匹数
  6. 假如把T中所有左部节点的顶标Ai减少一个数值,右部节点顶标Bi增加一个数值,访问到的节点有何变化
  7. 对于T中匹配边,显然没有变化
  8. 对于T中非匹配边,如果i,j都在T中,显然没有变化
  9. 如果i在T中,j不在T中,则Ai+Bj减少,即以前从i访问不到的点j现在可能访问到了
  10. 为保证顶标符合条件,我们要找出最小的Ai+Bj-w(i,j),作为(6)中减去的数值
  11. 这样不断减小一些Ai+Bj的值,直到达到完备匹配,即为最大带全匹配

Code


bool dfs(int x){
	la[x]=true;
	rep(y,1,n) if(!lb[y])
		if(a[x]+b[y]==w[x][y]){
			lb[y]=1;
			if(!match[y]||dfs(match[y])){
				match[y]=x;
				return true;
			}
		}
	else delta=min(delta,a[x]+b[y]-w[x][y]);
	return false;
}
int KM(){
	rep(i,1,n){
		a[i]=-inf,b[i]=0;
		rep(j,1,n) a[i]=max(a[i],w[i][j]);
	}
	rep(i,1,n) while(true){
		memset(la,false,sizeof(la));
		memset(lb,false,sizeof(lb));
		delta=inf;
		if(dfs(i))break;
		rep(i,1,n)a[i]-=delta,b[i]+=delta;
	}
	int ans=0;
	rep(i,1,n)ans+=w[match[i]][i];
	return ans;
}

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值