pku2195

来源:互联网 发布:iPhone如何传照片到Mac 编辑:程序博客网 时间:2024/06/08 17:47

/*
 * File:   main.cpp
 * Author: chenjiang
 *最小费用最大流,直接套模版
 * Created on 2010年4月23日, 下午9:17
 */

#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
#define _max 300
#define inf 314748364
int mapmap[_max][_max], cost[_max][_max], n, m;
int flow[_max][_max], min_flow[_max];
int house_index, people_index;
int N, source, sink; //图的顶点数   超级源点    超级汇点
int dist[_max], pre[_max];
int sum_cost, sum_flow;

struct House {
    int x, y;
} house[_max];

struct People {
    int x, y;
} people[_max];
bool visited[_max];

int MIN(int a, int b) {
    if (a <= b)return a;
    else
        return b;
}

bool SPFA() {
    int i, j, k;
    memset(visited, 0, sizeof (visited));
    memset(pre, -1, sizeof (pre));
    queue<int> Q;
    for (i = source; i <= sink; i++) {
        dist[i] = inf;
    }
    dist[source] = 0;
    Q.push(source);
    visited[source] = 1;
    min_flow[source] = inf;
    while (!Q.empty()) {
        k = Q.front();
        Q.pop();
        visited[k] = 0;
        for (i = source; i <= sink; i++) {
            if ((mapmap[k][i] - flow[k][i] > 0) && (dist[k] + cost[k][i] < dist[i])) {
                dist[i] = dist[k] + cost[k][i];
                if (!visited[i]) {
                    Q.push(i);
                    visited[i] = 1;
                }
                pre[i] = k;
                min_flow[i] = MIN(min_flow[k], (mapmap[k][i] - flow[k][i]));

            }
        }
    }
    if (pre[sink] != -1)return 1;
    else return 0;
}

void mincost_maxflow() {
    sum_cost = 0, sum_flow = 0;
    memset(flow, 0, sizeof (flow));
    while (SPFA()) {
        int k = sink;
        while (k >= 0) {
            flow[pre[k]][k] += min_flow[sink];
            flow[k][pre[k]] = -flow[pre[k]][k];
            k = pre[k];
        }
        sum_cost += dist[sink];
        sum_flow += min_flow[sink];
    }
}

/*
 *
 */
int main(int argc, char** argv) {

    int i, j, k;
    char ch[105][105];
    //freopen("a.a", "r", stdin);
    while (cin >> n >> m) {
        if (n == 0 && m == 0)break;
        house_index = people_index = 0;
        for (i = 0; i < n; i++) {
            cin >> ch[i];
            for (j = 0; j < m; j++) {
                if (ch[i][j] == 'H')//当前点有一座房子,增加房子
                {
                    house_index++; //房子的个数加1
                    house[house_index].x = i; //保存房子的行坐标
                    house[house_index].y = j; //保存房子的列坐标
                } else if (ch[i][j] == 'm')//当前点是个人,增加人
                {
                    people_index++; //人的个数加1
                    people[people_index].x = i; //保存人的行坐标
                    people[people_index].y = j; //保存人的列坐标
                }
            }
        }
        memset(mapmap, 0, sizeof (mapmap));
        memset(cost, 0, sizeof (cost));
        source = 0; //超级源点为0
        sink = house_index + people_index + 1; //超级汇点
        N = sink + 1; //图的顶点个数
        for (i = 1; i <= house_index; i++) {
            for (j = 1; j <= people_index; j++) {
                //房子i到人j的费用
                cost[i][j + house_index] = abs(house[i].x - people[j].x) + abs(house[i].y - people[j].y);
                cost[j + house_index][i] = -cost[i][j + house_index]; //人j到房子i的费用
                mapmap[i][j + house_index] = 1; //房子和人之间连一条边
            }
        }
        for (i = 1; i <= house_index; i++) {
            mapmap[source][i] = 1;
        }
        for (i = 1; i <= people_index; i++) {
            mapmap[house_index + i][sink] = 1;
        }
        mincost_maxflow();
        cout << sum_cost << endl;
    }
    return (EXIT_SUCCESS);
}