KM算法是在匈牙利算法的基础上扩展出来的,具体原理不再赘述,算法模版如下:
#include
#include
#include
using namespace std;
const int MAX_X = 1024;
const int MAX_Y = 1024;
int n, m; // X ,Y 的大小
int weight[MAX_X][MAX_Y]; // X 到 Y 的映射(权重)
int lx[MAX_X], ly[MAX_Y]; // 标号
bool sx[MAX_X], sy[MAX_Y]; // 是否被搜索过
int match[MAX_Y]; // Y(i) 与 X(match [i]) 匹配
void init(){
for(int i = 0; i < n; i ++)
for(int j = 0; j < m; j ++)
scanf("%d", &weight[i][j]);
}
//寻找增广路径
bool hungary(int u){
sx[u] = true;
for(int v = 0; v < m; v ++)
if(!sy [v] && lx[u] + ly[v] == weight[u][v]){
sy[v] = true;
if(match[v] == -1 || hungary(match[v])){
match [v] = u;
return true;
}
}
return false;
}
int KM(bool maxsum){ // 参数 maxsum 为 true ,返回最大权匹配,否则最小权匹配
int i, j;
if(!maxsum){
for(i = 0; i < n; i ++)
for(j = 0; j < m; j ++)
weight [i] [j] = -weight [i] [j];
}
// 初始化标号
memset(ly, 0, sizeof(ly));
for(i = 0; i < n; i ++){
lx[i] = -0x7FFFFFFF;
for(j = 0; j < m; j ++)
lx[i] = max(weight[i][j], lx[i]);
}
memset(match, -1, sizeof(match));
for(int u = 0; u < n; u ++){
while(1){
memset(sx, 0, sizeof(sx));
memset(sy, 0, sizeof(sy));
if(hungary(u)) break;
// 修改标号
int d = 0x7FFFFFFF;
for(i = 0; i < n; i++)
if(sx[i])
for(j = 0; j < m; j ++)
if(!sy[j])
d = min(lx[i] + ly[j] - weight[i][j], d);
for(i = 0; i < n; i ++) if(sx[i]) lx[i] -= d;
for(i = 0; i < m; i ++) if(sy[i]) ly[i] += d;
}
}
int sum = 0;
for(i = 0; i < m; i ++)
sum += weight[ match[i] ][i];
if(!maxsum){
sum = -sum;
for(i = 0; i < n; i ++)
for(j = 0; j < m; j ++)
weight[i][j] = -weight[i][j]; // 如果需要保持 weight [ ] [ ] 原来的值,这里需要将其还原
}
return sum;
}
int main(){
while(~scanf("%d %d", &n, &m)){
init();
printf("%d\n", KM(false));
for(int i = 0; i < m; i ++)
printf("X %d -> Y %d\n", match [i], i);
}
return 0;
}
URL:http://acm.hdu.edu.cn/showproblem.php?pid=2255
对模版稍做修改即可:
#include
#include
#include
using namespace std;
const int MAX = 310;
int n;
int weight[MAX][MAX];
int lx[MAX], ly[MAX];
bool sx[MAX], sy[MAX];
int match[MAX];
void init(){
for(int i = 0; i < n; i ++)
for(int j = 0; j < n; j ++)
scanf("%d", &weight[i][j]);
}
bool hungary(int u){
sx[u] = true;
for(int v = 0; v < n; v ++)
if(!sy [v] && lx[u] + ly[v] == weight[u][v]){
sy[v] = true;
if(match[v] == -1 || hungary(match[v])){
match [v] = u;
return true;
}
}
return false;
}
int KM(){
int i, j;
memset(ly, 0, sizeof(ly));
for(i = 0; i < n; i ++){
lx[i] = -0x7FFFFFFF;
for(j = 0; j < n; j ++)
lx[i] = max(weight[i][j], lx[i]);
}
memset(match, -1, sizeof(match));
for(int u = 0; u < n; u ++){
while(1){
memset(sx, 0, sizeof(sx));
memset(sy, 0, sizeof(sy));
if(hungary(u)) break;
int d = 0x7FFFFFFF;
for(i = 0; i < n; i++)
if(sx[i])
for(j = 0; j < n; j ++)
if(!sy[j])
d = min(lx[i] + ly[j] - weight[i][j], d);
for(i = 0; i < n; i ++) if(sx[i]) lx[i] -= d;
for(i = 0; i < n; i ++) if(sy[i]) ly[i] += d;
}
}
int sum = 0;
for(i = 0; i < n; i ++)
sum += weight[ match[i] ][i];
return sum;
}
int main(){
while(~scanf("%d", &n)){
init();
printf("%d\n", KM());
}
return 0;
}
例题2 POJ 2195 Going Home
URL:http://poj.org/problem?id=2195
Description
Input
Output
Sample Input
2 2 .m H. 5 5 HH..m ..... ..... ..... mm..H 7 8 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 0 0
Sample Output
2 10 28
除了初始化数据,此题对模版的修改也不大:
#include
#include
#include
using namespace std;
const int MAXN = 110;
struct point{
int x;
int y;
}px[MAXN],py[MAXN];
char map[MAXN];
int r, c, n, m;
int weight[MAXN][MAXN];
int lx[MAXN], ly[MAXN];
bool sx[MAXN], sy[MAXN];
int match[MAXN];
void init(){
n = 0; m = 0;
for(int i = 0; i < r; i ++){
scanf("%s", map);
for(int j = 0; j < c; j ++)
if(map[j] == 'H')
px[n].x = i, px[n++].y = j;
else if(map[j] == 'm')
py[m].x = i, py[m++].y = j;
}
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
weight[i][j] = -(abs(px[i].x - py[j].x) + abs(px[i].y - py[j].y));
}
bool hungary(int u){
sx[u] = true;
for(int v = 0; v < m; v ++)
if(!sy [v] && lx[u] + ly[v] == weight[u][v]){
sy[v] = true;
if(match[v] == -1 || hungary(match[v])){
match [v] = u;
return true;
}
}
return false;
}
int KM(){
int i, j;
memset(ly, 0, sizeof(ly));
for(i = 0; i < n; i ++){
lx[i] = -0x7FFFFFFF;
for(j = 0; j < m; j ++)
lx[i] = max(weight[i][j], lx[i]);
}
memset(match, -1, sizeof(match));
for(int u = 0; u < n; u ++){
while(1){
memset(sx, 0, sizeof(sx));
memset(sy, 0, sizeof(sy));
if(hungary(u)) break;
int d = 0x7FFFFFFF;
for(i = 0; i < n; i++)
if(sx[i])
for(j = 0; j < m; j ++)
if(!sy[j])
d = min(lx[i] + ly[j] - weight[i][j], d);
for(i = 0; i < n; i ++) if(sx[i]) lx[i] -= d;
for(i = 0; i < m; i ++) if(sy[i]) ly[i] += d;
}
}
int sum = 0;
for(i = 0; i < m; i ++)
sum += weight[ match[i] ][i];
return -sum;
}
int main(){
while(~scanf("%d %d", &r, &c) && (r || c) ){
init();
printf("%d\n", KM());
}
return 0;
}