#include<cstdio>
#include<cstring>
using namespace std;
const int N = 50, INF = 1e9;
int nx, ny;
bool adj[N][N];
int v[N][N];
bool vx[N], vy[N];
int mx[N], my[N];
int lx[N], ly[N], slack[N];
void init(){
scanf("%d%d", &nx, &ny);
for(int i=0; i<nx; i++) for(int j=0; j<ny; j++) scanf("%d", &v[i][j]), adj[i][j] = (v[i][j]>0);
}
bool match(int x){
vx[x] = 1;
for(int y=0; y<ny; y++) if(adj[x][y] && !vy[y]){
int t = lx[x] + ly[y] - v[x][y];
if(t==0){
vy[y] = 1;
if(my[y]==-1 || match(my[y])){
mx[x] = y; my[y] = x; return 1;
}
}
else if(t<slack[y]) slack[y]=t;
}
return 0;
}
int KM(){
memset(lx, 0, sizeof(lx));
memset(ly, 0, sizeof(ly));
for(int i=0; i<nx; i++) for(int j=0; j<ny; j++) if(adj[i][j] && v[i][j]>lx[i]) lx[i]=v[i][j];
memset(mx, -1, sizeof(mx));
memset(my, -1, sizeof(my));
for(int x=0; x<nx; x++){
for(int y=0; y<ny; y++) slack[y] = INF;
for(;;){
memset(vx, 0, sizeof(vx));
memset(vy, 0, sizeof(vy));
if(match(x)) break;
int aug = INF;
for(int y=0; y<ny; y++) if(!vy[y] && slack[y]<aug) aug = slack[y];
for(int i=0; i<nx; i++) if(vx[i]) lx[i] -= aug;
for(int y=0; y<ny; y++) if(vy[y]) ly[y] += aug; else slack[y]-=aug;
}
}
int ret = 0;
for(int x=0; x<nx; x++) ret += lx[x];
for(int y=0; y<ny; y++) ret += ly[y];
return ret;
}
int main(){
init();
printf("%d\n", KM());
return 0;
}
这里把整个匹配都讲的十分详细了。但里面讲KM这一块的标程,明白其中心思路就行,实现不太优美。
标程要看这里的。(上面都是借鉴的)