poj 2196 Going Home(最小费用最大流)

题意:一个row*col的矩阵,m表示人,H表示房子,.表示空地,人数和房子数相等,如下图:

        55

        HH..m
        .....
        .....
        .....
        mm..H
现在要让所有的人都进入不同的房子内,问总共最少走多少步?

 

思路:最小费用最大流。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cmath>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int Max = 205;
const int inf = 99999999;

struct{
    int r, c;
}man[Max], hou[Max];
int n, m, h, ans;
int cap[Max][Max], pre[Max];
int cost[Max][Max], dis[Max];
int que[Max];
bool vis[Max];

void MakeMap(){
    int i, j;
    n = 2 * m + 1;
    memset(cap, 0, sizeof(cap));
    for(i = 1; i <= m; i ++){
        cap[0][i] = 1;
        cost[0][i] = 0;
    }
    for(i = h+1; i <= 2*h; i ++){
        cap[i][n] = 1;
        cost[i][n] = 0;
    }
    for(i = 1; i <= m; i ++)
        for(j = 1; j <= h; j ++){
            cap[i][h+j] = inf;
            cost[i][h+j] = abs(man[i].r-hou[j].r) + abs(man[i].c-hou[j].c);
            cost[h+j][i] = -cost[i][h+j];     //  逆边记得加
        }
}

bool spfa(){
    int i, head = 0, tail = 1;
    for(i = 0; i <= n; i ++){
        dis[i] = inf;
        vis[i] = false;
    }
    dis[0] = 0;
    que[0] = 0;
    while(tail != head){
        int u = que[head];
        vis[u] = true;
        for(i = 1; i <= n; i ++){
            if(cap[u][i] && dis[i] > dis[u] + cost[u][i]){
                dis[i] = dis[u] + cost[u][i];
                pre[i] = u;
                if(!vis[i]){
                    vis[i] = true;
                    que[tail ++] = i;
                    if(tail == Max) tail = 0;
                }
            }
        }
        vis[u] = false;
        head ++;
        if(head == Max) head = 0;
    }
    if(dis[n] < inf) return true;    //  存在增广路径。
    return false;
}

void end(){
    int i, sum = inf;
    for(i = n; i != 0; i = pre[i])
        sum = min(sum, cap[pre[i]][i]);
    for(i = n; i != 0; i = pre[i]){
        cap[pre[i]][i] -= sum;
        cap[i][pre[i]] += sum;
        ans += cost[pre[i]][i] * sum;
    }
}

int main(){
    int row, col, r, c;
    char ch;
    while(scanf("%d%d",&row,&col)&&row){
        if(row == 0 && col == 0) break;
        m = 0, h = 0;
        for(r = 0; r < row; r ++)
         for(c = 0; c < col; c ++){
          scanf(" %c",&ch);//空白字符会略去输入中的一个或多个空白字符即读取非空字符
             if(ch == 'm'){
                 man[++ m].r = r;
                 man[m].c = c;
             }else if(ch == 'H'){
                 hou[++ h].r = r;
                 hou[h].c = c;
             }
         }
        MakeMap();
        ans = 0;
        while(spfa()) end();
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(poj 2196 Going Home(最小费用最大流))