Going Home POJ - 2195(最小费用流)
题目链接
题目大意:给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致。man每移动一格需花费1(即单位费用=单位距离),一间house只能入住一个man。现在要求所有的man都入住house,求最小费用。
样例:
2 2
.m
H.
5 5
HH..m
…..
…..
…..
mm..H
7 8
…H….
…H….
…H….
mmmHmmmm
…H….
…H….
…H….
0 0
输出:
2
10
28
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 10012+ 10;
const int INF = 0x3f3f3f3f;
struct node {
int u, to, w, cost, next;
} Edge[maxn << 2];
struct Point {
int x, y, flag;
};
vector<Point> p;
int Head[maxn], cnt, dist[maxn], flow[maxn], pre[maxn];
char str[maxn];
bool vis[maxn];
int GetDistance(Point a, Point b) {
return abs(a.x - b.x) + abs(a.y - b.y);
}
void add(int u, int v, int w) {
Edge[cnt] = (node) {u, v, 1, w, Head[u]};
Head[u] = cnt++;
Edge[cnt] = (node) {v, u, 0, -w, Head[v]};
Head[v] = cnt++;
}
bool spfa(int s, int e) {
queue<int> q;
q.push(s);
memset(dist, INF, sizeof(dist));
memset(vis, false, sizeof(vis));
dist[s] = 0;
vis[s] = true;
flow[s] = INF;
while(!q.empty()) {
int now = q.front();
q.pop();
vis[now] = false;
for(int i = Head[now]; ~i; i = Edge[i].next) {
int to = Edge[i].to, w = Edge[i].w, cost = Edge[i].cost;
if(w > 0 && dist[to] > dist[now] + cost) {
dist[to] = dist[now] + cost;
flow[to] = min(flow[now], w);
if(!vis[to]) {
q.push(to);
vis[to] = true;
}
pre[to] = i;
}
}
}
return dist[e] != INF;
}
int min_cost_flow(int s, int e) {
int res = 0;
while(spfa(s, e)) {
int u = e;
res += dist[e] * flow[e];
while(u != s) {
int now = pre[u];
Edge[now].w -= flow[e];
Edge[now ^ 1].w += flow[e];
u = Edge[now].u;
}
}
return res;
}
int main()
{
int n, m;
while(~scanf("%d %d", &n, &m) && (n + m)) {
p.clear();
for(int i = 0; i < n; i++) {
scanf("%s", str);
for(int j = 0; j < m; j++) {
if(str[j] == 'm') p.push_back((Point) {i, j, true});
if(str[j] == 'H') p.push_back((Point) {i, j, false});
}
}
cnt = 0;
memset(Head, -1, sizeof(Head));
int s = p.size(), e = s + 1;
for(int i = 0; i < s; i++) {
if(p[i].flag) {
add(s, i, 0);
for(int j = 0; j < s; j++) {
if(!p[j].flag) {
add(i, j, GetDistance(p[i], p[j]));
}
}
}
else add(i, e, 0);
}
int v = min_cost_flow(s, e);
printf("%d\n", v);
}
}