POJ 2195 Going Home(BFS+KM求最小权值)

Description:

On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need to pay a $1 travel fee for every step he moves, until he enters a house. The task is complicated with the restriction that each house can accommodate only one little man.

Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a ‘.‘ means an empty space, an ‘H‘ represents a house on that point, and am ‘m‘ indicates there is a little man on that point. 

You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.

Input:

There are one or more test cases in the input. Each case starts with a line giving two integers N and M, where N is the number of rows of the map, and M is the number of columns. The rest of the input will be N lines describing the map. You may assume both N and M are between 2 and 100, inclusive. There will be the same number of ‘H‘s and ‘m‘s on the map; and there will be at most 100 houses. Input will terminate with 0 0 for N and M.

Output:

For each test case, output one line with the single integer, which is the minimum amount, in dollars, you need to pay.

Sample Input:

2 2
.m
H.
5 5
HH..m
.....
.....
.....
mm..H
7 8
...H....
...H....
...H....
mmmHmmmm
...H....
...H....
...H....
0 0

Sample Output:

2
10
28

题意:有n个人和n个房子,现在要求这n个人分别回到n个房子所需要的最短路程是多少,地图中‘.‘代表空地,‘m‘代表人,‘H‘代表房子,m和H是对应的那么就必须先用BFS求得每个人到每个房子的最短距离,然后用KM算法计算每个人与房子的完备匹配得到最小权值
#include<stdio.h>
#include<queue>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define N 110
using namespace std;
char Map[N][N];
int n, m, K;
int G[N][N], s[N], lx[N], ly[N], no[N][N]; //no数组存放的是在第i行第j列的房子的序号
int use[N], visx[N], visy[N], V[N][N];
int dir[4][2] = { {1,0}, {-1,0}, {0,1}, {0,-1} };
struct node
{
    int x, y, z;
};
void BFS(int x, int y, int k)
{
    int nx, ny, i;
    memset(V, 0, sizeof(V));
    queue<node>Q;
    node now, next;
    now.x = x; now.y = y; now.z = 0;
    Q.push(now);
    while (!Q.empty())
    {
        now = Q.front();
        Q.pop();
        if (Map[now.x][now.y] == ‘H‘) //每遇到一个房子,就将第k个人到这所房子的距离记录下来
            G[k][no[now.x][now.y]] = -now.z; //因为要求最小权值,所以只要把两点间权值改为其相反数,再用KM求其最大匹配即可
        for (i = 0; i < 4; i++)
        {
            next.x = nx = now.x + dir[i][0];
            next.y = ny = now.y + dir[i][1];
            if (nx >= 0 && nx < n && ny >= 0 && ny < m && !V[nx][ny])
            {
                V[nx][ny] = 1;
                next.z = now.z + 1;
                Q.push(next);
            }
        }
    }
}
int Find(int u)
{
    int i;
    visx[u] = 1;
    for (i = 1; i <= K; i++)
    {
        if (!visy[i] && G[u][i] == lx[u]+ly[i])
        {
            visy[i] = 1;
            if (!use[i] || Find(use[i]))
            {
                use[i] = u;
                return 1;
            }
        }
        else s[i] = min(s[i], (lx[u]+ly[i])-G[u][i]);
    }
    return 0;
}
int KM()
{
    int i, j, ans = 0, d;
    memset(lx, 0, sizeof(lx));
    memset(ly, 0, sizeof(ly));
    for (i = 1; i <= K; i++)
        for (j = 1; j <= K; j++)
            lx[i] = max(lx[i], G[i][j]);
    for (i = 1; i <= K; i++)
    {
        for (j = 1; j <= K; j++)
            s[j] = INF;
        while (1)
        {
            memset(visx, 0, sizeof(visx));
            memset(visy, 0, sizeof(visy));
            if (Find(i)) break;
            d = INF;
            for (j = 1; j <= K; j++)
            {
                if (!visy[j])
                    d = min(s[j], d);
            }
            for (j = 1; j <= K; j++)
            {
                if (visx[j])
                    lx[j] -= d;
                if (visy[j])
                    ly[j] += d;
            }
        }
    }
    for (i = 1; i <= K; i++)
        ans -= G[use[i]][i]; //计算结果时不要忘记G数组存放的是负数
    return ans;
}
int main ()
{
    int i, j, k, ans, t;
    while (scanf("%d%d", &n, &m), n+m)
    {
        k = 0;
        t = 0;
        memset(G, 0, sizeof(G));
        memset(use, 0, sizeof(use));
        for (i = 0; i < n; i++)
            scanf("%s", Map[i]);
        for (i = 0; i < n; i++)
            for (j = 0; j < m; j++)
                if (Map[i][j] == ‘H‘)
                    no[i][j] = ++t;
        for (i = 0; i < n; i++)
        {
            for (j = 0; j < m; j++)
            {
                if (Map[i][j] == ‘m‘)
                {
                    BFS(i, j, ++k); //每遇到一个人就进行BFS,得到这个人到每个房子的距离
                    K = k; //K是人的序号
                }
            }
        }
        ans = KM();
        printf("%d\n", ans);
    }
    return 0;
}
时间: 2024-08-24 03:07:43

POJ 2195 Going Home(BFS+KM求最小权值)的相关文章

【POJ 2400】 Supervisor, Supervisee(KM求最小权匹配)

[POJ 2400] Supervisor, Supervisee(KM求最小权匹配) Supervisor, Supervisee Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2538   Accepted: 719 Description Suppose some supervisors each get to hire a new person for their department. There are N

ural 1076 KM求最小权匹配

贴模板~ KM算法引进了顶标函数,不断缩小这个顶标来让相等子图的可能范围扩大 #include<iostream> #include<cstring> //KM 复杂度O^3 using namespace std; const int N=200; int lx[N],ly[N];//顶标函数 int w[N][N];//图 bool vix[N],viy[N]; int linky[N];// int lack;//每次顶标函数扩大的增量 int n,m; bool find(

最小生成树 --- 求最小权值、MST

Agri-Net Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 37109   Accepted: 14982 Description Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He nee

POJ 2253 Frogger(Dijkstra变形——最短路径最小权值)

题目链接: http://poj.org/problem?id=2253 Description Freddy Frog is sitting on a stone in the middle of a lake. Suddenly he notices Fiona Frog who is sitting on another stone. He plans to visit her, but since the water is dirty and full of tourists' suns

POJ-2195 Going Home---KM算法求最小权值匹配(存负边)

题目链接: https://vjudge.net/problem/POJ-2195 题目大意: 给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致.man每移动一格需花费$1(即单位费用=单位距离),一间house只能入住一个man.现在要求所有的man都入住house,求最小费用. 思路: KM算法传送门: 理解篇    运用篇 每个man和house建立带权二分图,曼哈顿距离就是边的值,这里要求最小费用,也就是二分图最小权值匹配,但是KM算法求的是二分图最

【POJ 2195】 Going Home(KM算法求最小权匹配)

[POJ 2195] Going Home(KM算法求最小权匹配) Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 20303   Accepted: 10297 Description On a grid map there are n little men and n houses. In each unit time, every little man can move one unit ste

POJ 2195 Going Home 【二分图最小权值匹配】

传送门:http://poj.org/problem?id=2195 Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 26151   Accepted: 13117 Description On a grid map there are n little men and n houses. In each unit time, every little man can move one unit st

poj3565 Ants km算法求最小权完美匹配,浮点权值

/** 题目:poj3565 Ants km算法求最小权完美匹配,浮点权值. 链接:http://poj.org/problem?id=3565 题意:给定n个白点的二维坐标,n个黑点的二维坐标. 求是否存在n条边,每条边恰好连一个白点,一个黑点,且所有的边不相交. 输出所有黑点连接的白点编号. 思路:最小权完美匹配. 假定有白点1(a1,b1), 2(a2,b2), 黑点3(a3,b3),4(a4,b4); 如果1(a1,b1)与3(a3,b3)相连,2(a2,b2)与4(a4,b4)相连,如

POJ 3686 The Windy&#39;s 最小权值匹配

点击打开链接 The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3788   Accepted: 1630 Description The Windy's is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receives N orders for toys.