带权匹配是指在最大匹配的基础上,使匹配边的边权和最大。一般有两种写法,一个是KM算法(只针对可以完备匹配的二分图),一个是费用流。
KM算法在稠密图上比费用流更优秀一些,不过应用范围太小,所以还是鼓励大家用费用流。当然啦,作为一种算法KM也是我们需要了解的(况且我不会网络流??)。
KM算法有个流程:
1、存图
2、用贪心算法初始化标杆
3、运用匈牙利算法找到完备匹配
4、如果找不到完备匹配,通过修改标杆增加一些边
5、重复做3和4两个步骤,直到找到完备匹配。
其他的话,我表述的也不是很好,理解有限抱歉。有一篇很好的博客,推荐一下:http://www.cnblogs.com/Lanly/p/6291214.html
#include<bits/stdc++.h> using namespace std; const int N=105; int n,ans,delta,w[N][N],match[N],la[N],lb[N],va[N],vb[N]; bool dfs(int x){ va[x]=1; for(int y=1;y<=n;++y){ if(!vb[y]){ if(va[x]+vb[y]-w[x][y]==0){ vb[y]=1; if(!match[y]||dfs(match[y])){ match[y]=x; return true; } }else delta=min(delta,la[x]+lb[y]-w[x][y]); } } return false; } int KM(){ for(int i=1;i<=n;++i){ la[i]=-(1<<30); lb[i]=0; for(int j=1;j<=n;++j) la[i]=max(la[i],w[i][j]); } for(int i=1;i<=n;++i){ while(true){ memset(va,0,sizeof(va)); memset(vb,0,sizeof(vb)); delta=1<<30; if(dfs(i)) break; for(int j=1;j<=n;++j){ if(va[j]) la[j]-=delta; if(vb[j]) lb[j]-=delta; } } } ans=0; for(int i=1;i<=n;++i) ans+=w[match[i]][i]; return ans; } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) scanf("%d",&w[i][j]); printf("%d\n",KM()); return 0; }
原文地址:https://www.cnblogs.com/kgxw0430/p/10221972.html
时间: 2024-11-05 18:42:31