Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1415 Accepted Submission(s): 698
2 2 .m H. 5 5 HH..m ..... ..... ..... mm..H 7 8 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 0 0
2 10 28
题目大意:输入一幅图,图中有n个H和n个m分别代表有n个人和n个住所,人去住所需要花费金钱,移动一格需要一个费用,一格住所只能容纳一个人,问n个人都去到住所最低花费是多少?
求最低费用时,只要讲费用全部变成负数,然后按照原来那样求最大值,得出的结果再变成正数就是最后答案了,求最大值和最小值都是一样道理。
赤裸裸的最大权匹配问题,先建好图,然后一个模板套上去就OK了。
代码如下:
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> using namespace std; #define MAXN 100 #define INF 99999999 struct node { int x, y; }M[MAXN], H[MAXN]; char map[MAXN][MAXN]; int w[MAXN][MAXN]; int lx[MAXN], ly[MAXN]; bool sx[MAXN], sy[MAXN]; int pre[MAXN], slack[MAXN]; int n, m, mn, hn; int dis(node a, node b) { int dis = abs(a.x-b.x) + abs(a.y-b.y); return dis; } void bulid() { int i, j; mn = hn = 0; for(i = 0; i < n; i++) { for(j = 0; j < m; j++) { cin >> map[i][j]; if(map[i][j] == 'm') { M[mn].x = i; M[mn].y = j; mn++; } if(map[i][j] == 'H') { H[hn].x = i; H[hn].y = j; hn++; } } } memset(w, 0, sizeof(w)); for(i = 0; i < mn; i++) for(j = 0; j < hn; j++) w[i][j] = -dis(M[i], H[j]); } int dfs(int u) { sx[u] = true; for(int i = 0; i < hn; i++) { if(sy[i]) continue; int tp = lx[u] + ly[i] - w[u][i]; if(!tp) { sy[i] = true; if(pre[i] == -1 || dfs(pre[i])) { pre[i] = u; return 1; } } else if(slack[i] > tp) slack[i] = tp; } return 0; } int KM() { int i, j, k, d, res = 0; memset(pre, -1, sizeof(pre)); memset(ly, 0, sizeof(ly)); for(i = 0; i < mn; i++) { lx[i] = -INF; for(j = 0; j < hn; j++) lx[i] = max(lx[i], w[i][j]); } for(k = 0; k < mn; k++) { for(i = 0; i < hn; i++) slack[i] = INF; while(1) { memset(sx, false, sizeof(sx)); memset(sy, false, sizeof(sy)); if(dfs(k)) break; d = INF; for(i = 0; i < hn; i++) if(!sy[i]) d = min(d, slack[i]); for(i = 0; i < mn; i++) if(sx[i]) lx[i] -= d; for(i = 0; i < hn; i++) if(sy[i]) ly[i] += d; } } res = 0; for(i = 0; i < hn; i++) res += w[pre[i]][i]; return -res; } int main() { int ans; while(scanf("%d %d", &n, &m) != EOF) { if(!n && !m) break; bulid(); ans = KM(); printf("%d\n", ans); } return 0; }