题意:一个n*n的矩阵每个格子里有一个正整数w(i,j)你的任务是确定每行一个整数row(i)每列一个整数col(i),对每个格子都有w(i,j)<=row(i)+col(j)所有row(i)和col(i)和尽量小。
思路:本题利用KM算法l(x)+l(y)>=w(x,y)的性质直接可以知道得出的顶标之和即为最小的。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
const int INF=0x3f3f3f3f;
using namespace std;
int s[505][505],visx[505],visy[505],match[505];
int lx[505],ly[505];
int n,m;
int hungarian(int x){
int i;
visx[x]=1;
for(i=1;i<=m;i++){
if(!visy[i]&&lx[x]+ly[i]==s[x][i]){
visy[i]=1;
if(!match[i]||hungarian(match[i])){
match[i]=x;
return 1;
}
}
}
return 0;
}
int KM(){
int i,j,k,sum,temp;
sum=0;
memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
memset(match,0,sizeof(match));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
lx[i]=max(lx[i],s[i][j]);
for(i=1;i<=n;i++){
while(1){
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(hungarian(i))
break;
else{
temp=INF;
for(j=1;j<=n;j++)
if(visx[j]){
for(k=1;k<=m;k++)
if(!visy[k])
temp=min(temp,lx[j]+ly[k]-s[j][k]);
}
if(temp==INF)
return -1;
for(j=1;j<=n;j++)
if(visx[j])
lx[j]-=temp;
for(j=1;j<=m;j++)
if(visy[j])
ly[j]+=temp;
}
}
}
for(i=1;i<=m;i++)
if(match[i]!=0){
if(s[match[i]][i]!=-INF)
sum+=s[match[i]][i];
else
return -1;
}
return sum;
}
int main(){
int i,j,a,b,c,ans,num;
while(scanf("%d",&n)!=EOF){
m=n;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
s[i][j]=-INF;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++){
scanf("%d",&num);
s[i][j]=num;
}
ans=KM();
for(i=1;i<=n;i++)
printf("%d ",lx[i]);
printf("\n");
for(i=1;i<=m;i++)
printf("%d ",ly[i]);
printf("\n");
printf("%d\n",ans);
}
return 0;
}原文:http://blog.csdn.net/dan__ge/article/details/51277493