题目链接:https://cn.vjudge.net/problem/HDU-1533

题意:给你n个房子n个人  使得所有人都有一座房子的最小花费

思路:把所有的人与房子建边,最后,源点与所有的人建边,所有的房子与汇点,跑一边最消费用最大流即可

 

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#define ll long long
#define INF 0x3f3f3f3f
const int maxn = 1e5+5;

using namespace std;

struct node{
    int to;
    int c;
    int cost;
    int next;
}e[maxn];

struct point {
    int x,y;
    point(){}
    point(int a,int b):x(a),y(b){}
};
vector<point> v1,v2;

int head[maxn],cnt,l,r,n,m;

bool vis[maxn];
int dis[maxn],pre[maxn];

void init() {
    v1.clear();v2.clear();
    memset(head,-1,sizeof(head));
    cnt=0;
}

void insert(int u,int v,int c,int w) {
    e[cnt].to = v;
    e[cnt].c = c;
    e[cnt].cost = w;
    e[cnt].next = head[u];
    head[u] = cnt++;
}
void addedge(int u,int v,int c,int w){
    insert(u,v,c,w);
    insert(v,u,0,-w);
}

char a[105][105];
void build() {
    init();
    for(int i=0;i<n;i++)
    for(int j=0;j<m;j++) {
        if(a[i][j]=='m')
            v1.push_back(point(i,j));
        else if(a[i][j]=='H')
            v2.push_back(point(i,j));
    }
    l = v1.size();
    r = v2.size();
    for(int i=0;i<l;i++) {
        point P = v1[i];
        int x = i+1;
        addedge(0,x,1,0);
        for(int j=0;j<r;j++) {
            point H = v2[j];
            int y = j+l+1;
            int d = abs(P.x-H.x) + abs(P.y-H.y);
            addedge(x,y,1,d);
            if(i==l-1) {
                addedge(y,l+r+1,1,0);
            }
        }
    }
}
bool SPFA(int s,int t) {
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    memset(dis,0x3f,sizeof(dis));
    queue<int> q;
    q.push(s);
    vis[s]=1;
    dis[s]=0;
    while(!q.empty()) {
        int x = q.front();
        q.pop();
        vis[x] = 0;
        for(int i = head[x];i!=-1;i = e[i].next) {
            int to = e[i].to;
            if(e[i].c && dis[to] > dis[x] + e[i].cost){
                dis[to] = dis[x] + e[i].cost;
                pre[to] = i;
                if(!vis[to]) {
                    vis[to] = 1;
                    q.push(to);
                }
            }

        }
    }
    return pre[t] != -1;
}
int minCostMaxFLow(int s,int t) {
    int ans = 0;
    while(SPFA(s,t)) {
        int flow = INF;
        for(int i = t; i != s; i = e[pre[i]^1].to) {
            flow = min(flow, e[pre[i]].c);
            //cout<<flow<<endl;
        }
        for(int i=t;i!=s;i = e[pre[i]^1].to) {
            e[pre[i]].c-=flow;
            e[pre[i]^1].c+=flow;
            ans += e[pre[i]].cost*flow;
        }
    }

    return ans;
}
int main()
{
    while(scanf("%d%d",&n,&m) &&n&&m) {
        for(int i=0;i<n;i++)
            scanf("%s",a[i]);
        build();
        printf("%d\n",minCostMaxFLow(0,l+r+1));
    }
    return 0;
}