链接:
https://vjudge.net/problem/POJ-2195
题意:
黄弘毅突然兴致大发准备免费送房子,m表示人,H表示房子,每个房子只能进一个人,房子数等于人数。黄弘毅为了方便起见决定要让所有人到自己的房子的距离和最小,请问这个距离和是多少?
思路:
最小费用最大流.
每个人连到每个房子.
代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <memory.h>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <stack>
#include <string>
#define MINF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int MAXN = 1e2+10;
const int INF = 1e9;
struct Edge
{
int from, to, flow, cap, cost;
Edge(int f, int t, int flo, int ca, int c):from(f), to(t), flow(flo), cap(ca), cost(c){}
};
vector<Edge> edges;
vector<int> G[MAXN*2];
pair<int, int > H[MAXN], P[MAXN];
int Dis[MAXN*2], Vis[MAXN*2], Pre[MAXN*2];
int n, m, s, t;
void AddEdge(int from, int to, int cap, int cost)
{
edges.push_back(Edge(from, to, 0, cap, cost));
edges.push_back(Edge(to, from, 0, 0, -cost));
G[from].push_back(edges.size()-2);
G[to].push_back(edges.size()-1);
}
int GetLen(int a, int b)
{
return abs(P[a].first-H[b].first)+abs(P[a].second-H[b].second);
}
bool SPFA()
{
//SPFA求最短路,处理负权
memset(Dis, MINF, sizeof(Dis));
memset(Vis, 0, sizeof(Vis));
queue<int> que;
Dis[s] = 0;
Vis[s] = 1;
que.push(s);
while (!que.empty())
{
int u = que.front();
que.pop();
Vis[u] = 0;
for (int i = 0;i < G[u].size();i++)
{
Edge &e = edges[G[u][i]];
if (e.cap > e.flow && Dis[e.to] > Dis[u]+e.cost)
{
Dis[e.to] = Dis[u]+e.cost;
Pre[e.to] = G[u][i];
if (!Vis[e.to])
{
Vis[e.to] = 1;
que.push(e.to);
}
}
}
}
if (Dis[t] != MINF)
return true;
return false;
}
int CostFlow()
{
int cost = 0;
while (SPFA())
{
int Min = INF;
for (int i = t;i != s;i = edges[Pre[i]].from)
{
Edge &e = edges[Pre[i]];
Min = min(Min, edges[Pre[i]].cap-edges[Pre[i]].flow);
}
for (int i = t;i != s;i = edges[Pre[i]].from)
{
edges[Pre[i]].flow += Min;
edges[Pre[i]^1].flow -= Min;
}
cost += Dis[t];
}
return cost;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
while (cin >> n >> m && n)
{
int cntp = 0, cnth = 0;
for (int i = s;i <= t;i++)
G[i].clear();
edges.clear();
for (int i = 1;i <= n;i++)
{
for (int j = 1;j <= m;j++)
{
char op;
cin >> op;
if (op == 'H')
H[++cnth].first = i, H[cnth].second = j;
if (op == 'm')
P[++cntp].first = i, P[cntp].second = j;
}
}
//people i*2-1, home i*2
for (int i = 1;i <= cntp;i++)
{
for (int j = 1;j <= cnth;j++)
{
// cout << GetLen(i, j) << endl;
AddEdge(i*2-1, j*2, 1, GetLen(i, j));
}
}
for (int i = 1;i <= cntp;i++)
AddEdge(0, i*2-1, 1, 0);
for (int i = 1;i <= cnth;i++)
AddEdge(i*2, 2*cnth+1, 1, 0);
s = 0, t = 2*cnth+1;
int res = CostFlow();
cout << res << endl;
}
return 0;
}