传送门:hdu2255
KM算法模板题
推荐两篇博客:
KM算法 详解+模板-Chierush (理论讲解清晰,附带模板)
km算法入门-logosG (有算法的模拟和详细图解)
#include
using namespace std;
const int N=330,inf=0x3f3f3f3f;
int n,tim,g[N][N],bel[N];
int slack[N],vis[2][N],tg[2][N];
bool dfs(int x)
{
int i,j;vis[0][x]=tim;
for(int i=1;i<=n;++i) if(vis[1][i]!=tim){
j=tg[0][x]+tg[1][i]-g[x][i];
if(!j){
vis[1][i]=tim;//选用后再标记vis
if(!bel[i] || dfs(bel[i])){
bel[i]=x;return true;
}
}else slack[i]=min(slack[i],j);//更新slack,保证最小
}
return false;
}
inline int KM()
{
int x,i,j,d,re=0;tim=0;
memset(tg,0,sizeof(tg));
memset(bel,0,sizeof(bel));
memset(vis,0,sizeof(vis));
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
tg[0][i]=max(tg[0][i],g[i][j]);//初始化点集S的标号
for(x=1;x<=n;++x){
memset(slack,0x3f,sizeof(slack));//初始化为inf
for(;;){
tim++;
if(dfs(x)) break;
d=inf;
for(i=1;i<=n;++i) if(vis[1][i]!=tim)
d=min(d,slack[i]);
for(i=1;i<=n;++i) if(vis[0][i]==tim)
tg[0][i]-=d;
for(i=1;i<=n;++i)
if(vis[1][i]==tim) tg[1][i]+=d;
else slack[i]-=d;
//以上为增广操作,注意slack[i]=tg[1][i]+tg[0][x(x属于S)]-w[x][i],tg[0][x]减小的同时slack[i]也要减小
}
}
for(i=1;i<=n;++i) if(bel[i])
re+=g[bel[i]][i];
return re;
}
int main(){
int i,j;
while(scanf("%d",&n)==1){
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
scanf("%d",&g[i][j]);
printf("%d\n",KM());
}
}