poj2195-二分图

题目链接:http://poj.org/problem?id=2195

Description
On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need to pay a $1 travel fee for every step he moves, until he enters a house. The task is complicated with the restriction that each house can accommodate only one little man.

Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a ‘.’ means an empty space, an ‘H’ represents a house on that point, and am ‘m’ indicates there is a little man on that point.
poj2195-二分图_第1张图片

You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.

Input

There are one or more test cases in the input. Each case starts with a line giving two integers N and M, where N is the number of rows of the map, and M is the number of columns. The rest of the input will be N lines describing the map. You may assume both N and M are between 2 and 100, inclusive. There will be the same number of ‘H’s and ‘m’s on the map; and there will be at most 100 houses. Input will terminate with 0 0 for N and M.

Output
For each test case, output one line with the single integer, which is the minimum amount, in dollars, you need to pay.

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

题意
给出一个矩阵,矩阵上m为人,H为房子,保证H的数量等于m,问所有人到达不同房子的最短距离之和。

思路
两个集合配对想到二分图没跑了,之前一直没搞过带权的,去网上学了一下发现还比较容易理解,自己的板子更新过后还是不错的,hhh。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lson l,mid,i<<1
#define rson mid+1,r,i<<1|1
using namespace std;
typedef long long ll;
const int maxn = 350;
const int INF = 2e9;
/* KM算法:复杂度O(nx*nx*ny)
* 完全二分图求最大权匹配(必须为所有girl找到对象,且数量必须girl<=boy数量)
* 若求最小权匹配,可将权值取相反数,结果取相反数
* 点的编号从1开始。
* 以男女模型出现比较直观。
*/
//左集为女,右集为男
int Lx[maxn];//第i个girl期望值
int Ly[maxn];//第i个boy期望值
int visx[maxn];//标记第i个girl是否被标记
int visy[maxn];//标记第i个bou是否被标记
int boy[maxn];//boy[i]记录i的匹配成功对象
int slack[maxn];
int mp[maxn][maxn];//二分图描述,mp[x][y]表示边权。
int Nx, Ny;//girl的个数和boy的个数
bool dfs(int u) {//当前的女孩编号
visx[u] = 1;
for (int i = 0; i < Ny; i++) {//枚举每个男孩
if (visy[i])
continue;
int g = Lx[u] + Ly[i] - mp[u][i];
if (g == 0) {
visy[i] = 1;
//为当前男的女对象另找男对象
if (boy[i] == -1 || dfs(boy[i])) {
boy[i] = u;
return 1;
}
}
else
slack[i] = min(slack[i], g);
}
return 0;
}
void update() {
int d = INF;
for (int i = 0; i < Ny; i++) {
if (!visy[i])
d = min(d, slack[i]);
}
for (int i = 0; i < Nx; i++) {
if (visx[i])
Lx[i] -= d;
}
for (int i = 0; i < Ny; i++) {
if (visy[i])
Ly[i] += d;
else
slack[i] -= d;
}
}
int km() {
memset(boy, -1, sizeof(boy));
memset(Ly, 0, sizeof(Ly));
for (int i = 0; i < Nx; i++) {
Lx[i] = -INF;
for (int j = 0; j < Ny; j++)
Lx[i] = max(Lx[i], mp[i][j]);
}
for (int i = 0; i < Nx; i++) {
fill(slack, slack + Nx, INF);
while (1) {
for (int i = 0; i < Ny; i++)
visx[i] = visy[i] = 0;
if (dfs(i))
break;
else
update();
}
}
int ans = 0;
for (int i = 0; i < Ny; i++)
ans += mp[boy[i]][i];
return ans;
}
struct node {
int x, y;
node() {}
node(int _x, int _y) { x = _x, y = _y; }
};
vectorhou;
vectorpe;
char s[maxn][maxn];
int main() {
int n, m;
while (cin >> n >> m) {
if (n == 0 && m == 0)
break;
for (int i = 0; i < n; i++)
scanf("%s", s[i]);
hou.clear();
pe.clear();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (s[i][j] == 'H') {
node t(i, j);
hou.push_back(t);
}
if (s[i][j] == 'm') {
node t(i, j);
pe.push_back(t);
}
}
}
int len = hou.size();
for (int i = 0; i < len; i++) {
for (int j = 0; j < len; j++) {
mp[i][j] = 5000 - (abs(hou[i].x - pe[j].x) + abs(hou[i].y - pe[j].y));
}
}
Nx = Ny = len;
printf("%d\n", 5000 * len - km());
}
}

谢谢你请我吃糖果

你可能感兴趣的:(poj2195-二分图)