题意:
图上,N个小矮人,N个房子,每个单位时间内
每个小矮人都能水平或者垂直移动一个单位步长到相邻的点。
每次移动消费1块钱,直到他进入房屋,每个房子只能容纳一个小矮人
问支付最低的金额。将这N个小矮人送入这N个不同的房间
数据范围:
1 s
N M < 100
N * M的矩阵, H是房子。m是人
思路:
为每个小矮人找到房子,
1)求最小权下的二分匹配
2)费用流:最小费用最大流
建图:源点 - 人 流量1, 费用0
人-房子 流量1,费用曼哈顿距离
房子-汇点 流量1,费用0
跑个费用流
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int N, M;
char G[150][150];
struct Point{
int x, y;
};
const int maxn = 505;
const int inf = 0x3f3f3f3f;
int path[maxn], dis[maxn], head[maxn], vis[maxn], cnt;
void init() {
cnt = 0;
memset(head, -1, sizeof(head));
}
struct node{
int v, flow, cost, nex;
}edge[maxn * maxn];
void addEdge(int u, int v, int flow, int cost) {
edge[cnt] = {v, flow, cost, head[u]};
head[u] = cnt++;
edge[cnt] = {u, 0, -cost, head[v]};
head[v] = cnt++;
}
int Spfa(int s, int t) {
memset(vis, 0, sizeof(vis));
memset(dis, inf, sizeof(dis));
memset(path, -1, sizeof(path));
queue que;
que.push(s);
dis[s] = 0;
vis[s] = 1;
while(!que.empty()) {
int u = que.front();
que.pop();
vis[u] = 0;
for(int i = head[u]; i != -1; i = edge[i].nex){
int v = edge[i].v;
int flow = edge[i].flow;
int cost = edge[i].cost;
if (flow > 0 && dis[v] > dis[u] + cost) {
dis[v] = dis[u] + cost;
path[v] = i;
if(vis[v]) continue;
vis[v] = 1;
que.push(v);
}
}
}
return dis[t] != inf;
}
int MCMF(int s, int t, int &cost) {
int maxflow = 0;
while(Spfa(s, t)) {
int flow = inf;
for (int i = path[t]; i != -1; i = path[edge[i ^ 1].v]) {
flow = min(flow, edge[i].flow);
}
for (int i = path[t]; i != -1; i = path[edge[i^1].v]) {
edge[i].flow -= flow;
edge[i^1].flow += flow;
cost += flow * edge[i].cost;
}
maxflow += flow;
}
return maxflow;
}
int Distance(Point a, Point b) {
return fabs(a.x - b.x) + fabs(a.y - b.y);
}
int main () {
Point People[maxn], House[maxn];
while(~scanf("%d%d", &N, &M) && N + M){
init();
for(int i = 0; i < N; ++i) {
scanf("%s", G[i]);
}
int CntP = 1;
int CntH = 1;
for (int i = 0; i < N; ++i) {
for (int j = 0; j < M; ++j) {
if(G[i][j] == 'm'){
People[CntP].x = i;
People[CntP].y = j;
CntP++;
}
else if(G[i][j] == 'H') {
House[CntH].x = i;
House[CntH].y = j;
CntH++;
}
}
}
for (int i = 1; i < CntP; ++i) {
for (int j = 1; j < CntH; ++j) {
int dis = Distance(People[i], House[j]);
addEdge(i, j + 100, 1, dis);
}
}
for(int i = 1; i < CntP; ++i) {
addEdge(0, i, 1, 0);
}
for(int j = 1; j < CntH; ++j) {
addEdge(j + 100, 201, 1, 0);
}
int Cost = 0;
int Ans = MCMF(0, 201, Cost);
printf("%d\n", Cost);
}
return 0;
}