/*
题目描述:题目给出一张n*m的地图,图中 . 表示空格,m表示人,H表示房间,人和房间的数量相同,人每移动一格的长度是1,现要求每个人进到
一间房中,使房间和人一一对应起来,问所有人最小的移动距离是多少。
方法:先用迪杰斯特拉预处理出每个人到每间房的距离;
再利用最小费用流,总共分四列:
第一列是源节点,连向所有的人,容量为1,费用为0;
第二列是人,从人连向每一间房,容量为1,费用为人到每间房的距离;
第三列是房间,每间房连向汇节点,容量为1,费用为0;
第四列为汇节点;
求出最小费用流即为答案。
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
int num = 0;
const int inf = 1000000000;
const int maxn = 100 + 5;
const int maxs = 10000 + 5;
int n,m;
int dis[maxn][maxn],id[maxn][maxn];
char mp[maxn][maxn];
typedef long long ll;
struct Edge
{
int from,to,cap,flow,cost;
};
struct MCMF
{
int n,m,s,t;
vector<Edge>edges;
vector<int>G[maxs];
int d[maxs],p[maxs],a[maxs],inq[maxs];
void init(int n)
{
this -> n = n;
for(int i=0;i<=n;i++) G[i].clear();
edges.clear();
}
void AddEdge(int from,int to,int cap,int cost)
{
Edge e1 = {from , to , cap , 0 , cost};
Edge e2 = {to , from , 0 , 0 , -cost};
edges.push_back(e1);
edges.push_back(e2);
int m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BellmanFord(int s,int t,int &flow , ll& cost)
{
for(int i=0;i<=n;i++){
d[i] = inf;
}
d[s] = 0; p[s] = 0; a[s] = inf;
mem(inq,0); inq[s] = 1;
queue<int>Q;
Q.push(s);
while(!Q.empty()){
int x = Q.front(); Q.pop();
inq[x] = 0;
for(int i= 0;i<G[x].size();i++){
Edge &e = edges[G[x][i]];
if(e.cap>e.flow && d[e.to]>d[x]+e.cost){
d[e.to] = d[x] + e.cost;
p[e.to] = G[x][i];
a[e.to] = min(a[x],e.cap - e.flow);
if(!inq[e.to]){
Q.push(e.to);
inq[e.to] = 1;
}
}
}
}
if(d[t]==inf) return false;
flow += a[t];
cost += (ll)a[t]*(ll)d[t];
int u = t;
while(u!=s){
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
u = edges[p[u]].from;
}
return true;
}
ll Mincost(int s,int t,int & flow)
{
flow = 0;
ll cost = 0;
while(BellmanFord(s,t,flow,cost)) ;
return cost;
}
};
MCMF g;
struct edge
{
int from , to , dist;
};
struct HeapNode
{
int u,d;
bool operator < (const HeapNode&rhs)const
{
return d>rhs.d;
}
};
struct Dijkstra
{
int n,m,s,t;
int d[maxs],p[maxs],vis[maxs];
vector<int>G[maxs];
vector<edge>edges;
void init(int n)
{
this -> n = n;
for(int i=0;i<=n;i++){
G[i].clear();
}
edges.clear();
}
void AddEdge(int from,int to,int dist)
{
edge e = {from,to,dist};
edges.push_back(e);
int m = edges.size();
G[from].push_back(m-1);
}
void dijkstra(int s)
{
for(int i=0;i<=n;i++) d[i] = inf;
priority_queue<HeapNode>Q;
HeapNode st = {s,0};
d[s] = 0;
mem(vis,0);
Q.push(st);
while(!Q.empty()){
HeapNode t = Q.top();
Q.pop();
int x = t.u;
if(vis[x]) continue;
vis[x] = 1;
for(int i=0;i<G[x].size();i++){
edge &e = edges[G[x][i]];
if(d[e.to]>d[x]+e.dist){
d[e.to] = d[x] + e.dist;
p[e.to] = G[x][i];
HeapNode nt;
nt = {e.to,d[e.to]};
Q.push(nt);
}
}
}
}
};
Dijkstra g2;
bool valid(int x,int y)
{
if(x<1||x>n||y<1||y>m)
return false;
return true;
}
int drx[]= {-1,1,0,0};
int dry[]={0,0,-1,1};
vector<int>house;
vector<int>man;
int main()
{
while(scanf("%d %d",&n,&m)!=EOF&&n){
for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
mem(id,0);
house.clear();
man.clear();
g2.init(n*m);
for(int i=1;i<=n;i++){
for(int j = 1;j<=m;j++){
id[i][j] = (i - 1)*m + j;
if(mp[i][j]=='H')
house.push_back(id[i][j]);
if(mp[i][j]=='m')
man.push_back(id[i][j]);
}
}
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
for(int k = 0;k<4;k++){
int nx = i + drx[k];
int ny = j + dry[k];
if(valid(nx,ny))
g2.AddEdge(id[i][j],id[nx][ny],1);
}
}
}
int len = man.size();
g.init(2*len + 1);
for(int i=0;i<len;i++){
int x = man[i];
g2.dijkstra(x);
for(int j = 0;j<len;j++){
int y = house[j];
g.AddEdge( i + 1 ,len + j + 1 , 1 , g2.d[y] );
}
}
int source = 0,sink = 2*len + 1;
for(int i=0;i<len;i++){
g.AddEdge( source , i+1 , 1 , 0);
g.AddEdge(len + i + 1,sink , 1 ,0);
}
int flow;
ll ans = g.Mincost(source,sink,flow);
printf("%lld\n",ans);
}
return 0;
}
题目描述:题目给出一张n*m的地图,图中 . 表示空格,m表示人,H表示房间,人和房间的数量相同,人每移动一格的长度是1,现要求每个人进到
一间房中,使房间和人一一对应起来,问所有人最小的移动距离是多少。
方法:先用迪杰斯特拉预处理出每个人到每间房的距离;
再利用最小费用流,总共分四列:
第一列是源节点,连向所有的人,容量为1,费用为0;
第二列是人,从人连向每一间房,容量为1,费用为人到每间房的距离;
第三列是房间,每间房连向汇节点,容量为1,费用为0;
第四列为汇节点;
求出最小费用流即为答案。
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
int num = 0;
const int inf = 1000000000;
const int maxn = 100 + 5;
const int maxs = 10000 + 5;
int n,m;
int dis[maxn][maxn],id[maxn][maxn];
char mp[maxn][maxn];
typedef long long ll;
struct Edge
{
int from,to,cap,flow,cost;
};
struct MCMF
{
int n,m,s,t;
vector<Edge>edges;
vector<int>G[maxs];
int d[maxs],p[maxs],a[maxs],inq[maxs];
void init(int n)
{
this -> n = n;
for(int i=0;i<=n;i++) G[i].clear();
edges.clear();
}
void AddEdge(int from,int to,int cap,int cost)
{
Edge e1 = {from , to , cap , 0 , cost};
Edge e2 = {to , from , 0 , 0 , -cost};
edges.push_back(e1);
edges.push_back(e2);
int m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BellmanFord(int s,int t,int &flow , ll& cost)
{
for(int i=0;i<=n;i++){
d[i] = inf;
}
d[s] = 0; p[s] = 0; a[s] = inf;
mem(inq,0); inq[s] = 1;
queue<int>Q;
Q.push(s);
while(!Q.empty()){
int x = Q.front(); Q.pop();
inq[x] = 0;
for(int i= 0;i<G[x].size();i++){
Edge &e = edges[G[x][i]];
if(e.cap>e.flow && d[e.to]>d[x]+e.cost){
d[e.to] = d[x] + e.cost;
p[e.to] = G[x][i];
a[e.to] = min(a[x],e.cap - e.flow);
if(!inq[e.to]){
Q.push(e.to);
inq[e.to] = 1;
}
}
}
}
if(d[t]==inf) return false;
flow += a[t];
cost += (ll)a[t]*(ll)d[t];
int u = t;
while(u!=s){
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
u = edges[p[u]].from;
}
return true;
}
ll Mincost(int s,int t,int & flow)
{
flow = 0;
ll cost = 0;
while(BellmanFord(s,t,flow,cost)) ;
return cost;
}
};
MCMF g;
struct edge
{
int from , to , dist;
};
struct HeapNode
{
int u,d;
bool operator < (const HeapNode&rhs)const
{
return d>rhs.d;
}
};
struct Dijkstra
{
int n,m,s,t;
int d[maxs],p[maxs],vis[maxs];
vector<int>G[maxs];
vector<edge>edges;
void init(int n)
{
this -> n = n;
for(int i=0;i<=n;i++){
G[i].clear();
}
edges.clear();
}
void AddEdge(int from,int to,int dist)
{
edge e = {from,to,dist};
edges.push_back(e);
int m = edges.size();
G[from].push_back(m-1);
}
void dijkstra(int s)
{
for(int i=0;i<=n;i++) d[i] = inf;
priority_queue<HeapNode>Q;
HeapNode st = {s,0};
d[s] = 0;
mem(vis,0);
Q.push(st);
while(!Q.empty()){
HeapNode t = Q.top();
Q.pop();
int x = t.u;
if(vis[x]) continue;
vis[x] = 1;
for(int i=0;i<G[x].size();i++){
edge &e = edges[G[x][i]];
if(d[e.to]>d[x]+e.dist){
d[e.to] = d[x] + e.dist;
p[e.to] = G[x][i];
HeapNode nt;
nt = {e.to,d[e.to]};
Q.push(nt);
}
}
}
}
};
Dijkstra g2;
bool valid(int x,int y)
{
if(x<1||x>n||y<1||y>m)
return false;
return true;
}
int drx[]= {-1,1,0,0};
int dry[]={0,0,-1,1};
vector<int>house;
vector<int>man;
int main()
{
while(scanf("%d %d",&n,&m)!=EOF&&n){
for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
mem(id,0);
house.clear();
man.clear();
g2.init(n*m);
for(int i=1;i<=n;i++){
for(int j = 1;j<=m;j++){
id[i][j] = (i - 1)*m + j;
if(mp[i][j]=='H')
house.push_back(id[i][j]);
if(mp[i][j]=='m')
man.push_back(id[i][j]);
}
}
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
for(int k = 0;k<4;k++){
int nx = i + drx[k];
int ny = j + dry[k];
if(valid(nx,ny))
g2.AddEdge(id[i][j],id[nx][ny],1);
}
}
}
int len = man.size();
g.init(2*len + 1);
for(int i=0;i<len;i++){
int x = man[i];
g2.dijkstra(x);
for(int j = 0;j<len;j++){
int y = house[j];
g.AddEdge( i + 1 ,len + j + 1 , 1 , g2.d[y] );
}
}
int source = 0,sink = 2*len + 1;
for(int i=0;i<len;i++){
g.AddEdge( source , i+1 , 1 , 0);
g.AddEdge(len + i + 1,sink , 1 ,0);
}
int flow;
ll ans = g.Mincost(source,sink,flow);
printf("%lld\n",ans);
}
return 0;
}