题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1533
先添加两个点s和t(源点汇点),图中的所有m和H可以看成是点。
建图过程:
1.s与图中所有的m之间建一条流量为1,费用为0的边。
2.图中所有的m与图中所有的H之间建一条流量为1,费用为dis(i,j)的边。dis表示两点之间的距离。
3.图中所有的H与s之间建一条流量为1,费用为0的边。
因此即为求s到t的最小费用流。
Dijkstra算法求最短路的代码:
#include <bits/stdc++.h>
using namespace std;
const int maxm=1e5+10;
const int maxn=1e4+10;
int n,m,tot,ct,hx[maxn],hy[maxn],mx[maxn],my[maxn];
int cnt,head[maxn],h[maxn],dis[maxn],prevv[maxn],preve[maxn];
typedef pair<int,int> P;
struct edge {
int to, next, cap, cost, rev;
}e[maxm];
int dist(int i,int j) {
return abs(hx[i] - mx[j]) + abs(hy[i] - my[j]);
}
void ins(int x,int y,int z,int c) {
e[++cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt;
e[cnt].cap = z;
e[cnt].rev = cnt + 1;
e[cnt].cost = c;
e[++cnt].to = x;
e[cnt].next = head[y];
head[y] = cnt;
e[cnt].cap = 0;
e[cnt].rev = cnt - 1;
e[cnt].cost = -c;
}
int min_cost_flow(int s,int t,int f) {
int ans = 0;
memset(h, 0, sizeof(h));
while (f > 0) {
priority_queue<P, vector<P>, greater<P> > q;
memset(dis, 63, sizeof(dis));
dis[s] = 0;
q.push(P(0, s));
while (!q.empty()) {
P p = q.top();
q.pop();
int v = p.second;
if (dis[v] < p.first)continue;
for (int i = head[v]; i; i = e[i].next) {
if (e[i].cap > 0 && dis[e[i].to] > dis[v] + e[i].cost + h[v] - h[e[i].to]) {
dis[e[i].to] = dis[v] + e[i].cost + h[v] - h[e[i].to];
prevv[e[i].to] = v;
preve[e[i].to] = i;
q.push(P(dis[e[i].to], e[i].to));
}
}
}
if (dis[t] > 1e8)
return -1;
for (int i = 0; i <= 1 + ct + tot; ++i)
h[i] += dis[i];
int d = f;
for (int i = t; i != s; i = prevv[i]) {
d = min(d, e[preve[i]].cap);
}
f -= d;
ans += d * h[t];
for (int i = t; i != s; i = prevv[i]) {
e[preve[i]].cap -= d;
e[e[preve[i]].rev].cap += d;
}
}
return ans;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
while (cin >> n >> m) {
if (n == 0)break;
memset(head, 0, sizeof(head));
tot = ct = cnt = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
char c;
cin >> c;
if (c == 'H') {
hx[++ct] = i;
hy[ct] = j;
}
if (c == 'm') {
mx[++tot] = i;
my[tot] = j;
}
}
}
int s = 0, t = tot + ct + 1;
for (int i = 1; i <= tot; ++i) {
ins(s, i, 1, 0);
}
for (int i = 1; i <= ct; ++i) {
ins(tot + i, t, 1, 0);
}
for (int i = 1; i <= tot; ++i) {
for (int j = 1; j <= ct; ++j) {
ins(i, tot + j, 1, dist(i, j));
}
}
cout << min_cost_flow(s, t, ct) << endl;
}
return 0;
}