我的AC代码
#include <iostream>
#include <string.h>
#include <vector>
#include <cmath>
using namespace std;
struct Node{
int x,y;
};
vector<Node> house,man;
int n,m;
int w[100][100];
int lm[100],lh[100],biaoji[100];
int s[100], t[100];
/*
w[i][j]表示第i个人到第j个房子所花费的费用
s[i]表示在每次寻找增广路的时候第i个人是否已经被访问到
t[i]表示在每次寻找增广路的时候第i个房子是否已经被访问到
biaoji[i]表示在当前匹配中第i个房子和第biaoji[i]个人匹配在一起
lm[i]表示第i个人的值
lh[i]表示第i个人的值
*/
int dis(Node a, Node b){ //此函数计算两点之间的距离,费用
return abs(a.x-b.x)+abs(a.y-b.y);
}
void init (){
house.clear();
man.clear();
memset(w, 0, sizeof(w));
memset(s, 0, sizeof(s));
memset(t, 0, sizeof(t));
for(int i = 0; i < n; i++){
char cs[100];
scanf("%s", cs);
for(int j = 0; j < m; j++){
if (cs[j]=='H') {
Node node;
node.x = i;
node.y = j;
house.push_back(node);
}
if (cs[j]=='m') {
Node node;
node.x = i;
node.y = j;
man.push_back(node);
}
}
}
for(int i = 0; i < man.size(); i++){
for(int j = 0; j < house.size(); j++){
w[i][j] = dis(man[i], house[j]);
}
}
for(int i = 0; i < man.size(); i++){
int result = INT_MAX;
for(int j = 0; j < house.size(); j++){
if (result > w[i][j]) {
result = w[i][j];
}
}
lm[i] = result;
}
for(int i = 0; i < house.size(); i++){
lh[i] = 0;
biaoji[i] = -1;
}
}
void update(){
int d = INT_MAX;
for(int i = 0; i < man.size(); i++){
if (s[i]==1) {
for(int j = 0; j < house.size(); j++){
if (t[j]==0 && d > w[i][j]-lm[i]-lh[j]) {
d = w[i][j]-lm[i]-lh[j];
}
}
}
}
for(int i = 0; i < man.size(); i++){
if (s[i]==1) {
lm[i] += d;
}
if (t[i]==1) {
lh[i] -= d;
}
}
}
bool find (int x){
s[x] = 1;
for (int i = 0; i < man.size(); i++) {
if (w[x][i]==lm[x]+lh[i] && t[i]==0) {
t[i] = 1;
if (biaoji[i]==-1 || find(biaoji[i])) {
biaoji[i] = x;
return true;
}
}
}
return false;
}
void km (){
for(int i = 0; i < man.size(); i++){
while (true) {
for(int j = 0; j < man.size(); j++){
s[j] = 0;
t[j] = 0;
}
if (find(i)) {
break;
}else{
update();
}
}
}
}
int main(int argc, const char * argv[])
{
while (scanf("%d %d", &n, &m)!=EOF) {
if (n+m==0) {
break;
}
init();
km();
int result = 0;
for(int i = 0; i < man.size(); i++){
result += lm[i];
result += lh[i];
}
printf("%d\n", result);
}
}
详细的思路请见这个博客
KM算法跟二分最大匹配还是很像的。其中find函数逻辑上是一模一样的。不同的地方就是,针对每一个人循环的过程中,要是没有找到增广路,则用update函数来调整人和房屋的值,使得更多的边满足w[i][j]==lm[i]+lh[j]这个等式,然后再找增广路,知道找到增广路为止(因为这是完全二分图,因此最坏的情况就是所有的边都加进来之后,才最终找到了增广路)。每个人都如此循环一下,循环结束时就意味着找到了权值最大的完美匹配。