标签:
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
题意:有n个人和n个房子,现在要求这n个人分别回到n个房子所需要的最短路程是多少,地图中‘.‘代表空地,‘m‘代表人,‘H‘代表房子,m和H是对应的
那么就必须先用BFS求得每个人到每个房子的最短距离,然后用KM算法计算每个人与房子的完备匹配得到最小权值
#include<stdio.h> #include<queue> #include<string.h> #include<algorithm> #define INF 0x3f3f3f3f #define N 110 using namespace std; char Map[N][N]; int n, m, K; int G[N][N], s[N], lx[N], ly[N], no[N][N]; //no数组存放的是在第i行第j列的房子的序号 int use[N], visx[N], visy[N], V[N][N]; int dir[4][2] = { {1,0}, {-1,0}, {0,1}, {0,-1} }; struct node { int x, y, z; }; void BFS(int x, int y, int k) { int nx, ny, i; memset(V, 0, sizeof(V)); queue<node>Q; node now, next; now.x = x; now.y = y; now.z = 0; Q.push(now); while (!Q.empty()) { now = Q.front(); Q.pop(); if (Map[now.x][now.y] == ‘H‘) //每遇到一个房子,就将第k个人到这所房子的距离记录下来 G[k][no[now.x][now.y]] = -now.z; //因为要求最小权值,所以只要把两点间权值改为其相反数,再用KM求其最大匹配即可 for (i = 0; i < 4; i++) { next.x = nx = now.x + dir[i][0]; next.y = ny = now.y + dir[i][1]; if (nx >= 0 && nx < n && ny >= 0 && ny < m && !V[nx][ny]) { V[nx][ny] = 1; next.z = now.z + 1; Q.push(next); } } } } int Find(int u) { int i; visx[u] = 1; for (i = 1; i <= K; i++) { if (!visy[i] && G[u][i] == lx[u]+ly[i]) { visy[i] = 1; if (!use[i] || Find(use[i])) { use[i] = u; return 1; } } else s[i] = min(s[i], (lx[u]+ly[i])-G[u][i]); } return 0; } int KM() { int i, j, ans = 0, d; memset(lx, 0, sizeof(lx)); memset(ly, 0, sizeof(ly)); for (i = 1; i <= K; i++) for (j = 1; j <= K; j++) lx[i] = max(lx[i], G[i][j]); for (i = 1; i <= K; i++) { for (j = 1; j <= K; j++) s[j] = INF; while (1) { memset(visx, 0, sizeof(visx)); memset(visy, 0, sizeof(visy)); if (Find(i)) break; d = INF; for (j = 1; j <= K; j++) { if (!visy[j]) d = min(s[j], d); } for (j = 1; j <= K; j++) { if (visx[j]) lx[j] -= d; if (visy[j]) ly[j] += d; } } } for (i = 1; i <= K; i++) ans -= G[use[i]][i]; //计算结果时不要忘记G数组存放的是负数 return ans; } int main () { int i, j, k, ans, t; while (scanf("%d%d", &n, &m), n+m) { k = 0; t = 0; memset(G, 0, sizeof(G)); memset(use, 0, sizeof(use)); for (i = 0; i < n; i++) scanf("%s", Map[i]); for (i = 0; i < n; i++) for (j = 0; j < m; j++) if (Map[i][j] == ‘H‘) no[i][j] = ++t; for (i = 0; i < n; i++) { for (j = 0; j < m; j++) { if (Map[i][j] == ‘m‘) { BFS(i, j, ++k); //每遇到一个人就进行BFS,得到这个人到每个房子的距离 K = k; //K是人的序号 } } } ans = KM(); printf("%d\n", ans); } return 0; }
POJ 2195 Going Home(BFS+KM求最小权值)
标签:
原文地址:http://www.cnblogs.com/syhandll/p/4718251.html