HDU 1533 KM算法(权值最小的最佳匹配)

Going Home

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3299    Accepted Submission(s): 1674

Problem 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

Source

Pacific Northwest 2004

题目意思:

给一个n*m的地图,‘m‘表示人,‘H‘表示房子,人每次能向上下左右走到邻近的单位,每次走一次总费用+1,每个房子只能容纳一个人,求当所有人走到房子后总费用最小为多少。

思路:

人放左边,房子放右边,之间的边权值表示人x[i]走到房子y[j]处花费的费用。权值弄成负数,KM找最佳匹配,答案在负一下即可。

代码:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <vector>
  6 #include <queue>
  7 #include <cmath>
  8 #include <set>
  9 using namespace std;
 10
 11 #define N 105
 12 #define inf 999999999
 13
 14 int max(int x,int y){return x>y?x:y;}
 15 int min(int x,int y){return x<y?x:y;}
 16 int abs(int x,int y){return x<0?-x:x;}
 17
 18 struct KM {
 19     int n, m;
 20     int g[N][N];
 21     int Lx[N], Ly[N], slack[N];
 22     int left[N], right[N];
 23     bool S[N], T[N];
 24
 25     void init(int n, int m) {
 26         this->n = n;
 27         this->m = m;
 28         memset(g, 0, sizeof(g));
 29     }
 30
 31     void add_Edge(int u, int v, int val) {
 32         g[u][v] += val;
 33     }
 34
 35     bool dfs(int i) {
 36         S[i] = true;
 37         for (int j = 0; j < m; j++) {
 38             if (T[j]) continue;
 39             int tmp = Lx[i] + Ly[j] - g[i][j];
 40             if (!tmp) {
 41                 T[j] = true;
 42                 if (left[j] == -1 || dfs(left[j])) {
 43                     left[j] = i;
 44                     right[i] = j;
 45                     return true;
 46                 }
 47             } else slack[j] = min(slack[j], tmp);
 48         }
 49         return false;
 50     }
 51
 52     void update() {
 53         int a = inf;
 54         for (int i = 0; i < m; i++)
 55             if (!T[i]) a = min(a, slack[i]);
 56         for (int i = 0; i < n; i++)
 57             if (S[i]) Lx[i] -= a;
 58         for (int i = 0; i < m; i++)
 59             if (T[i]) Ly[i] += a;
 60     }
 61
 62     int km() {
 63         memset(left, -1, sizeof(left));
 64         memset(right, -1, sizeof(right));
 65         memset(Ly, 0, sizeof(Ly));
 66         for (int i = 0; i < n; i++) {
 67             Lx[i] = -inf;
 68             for (int j = 0; j < m; j++)
 69                 Lx[i] = max(Lx[i], g[i][j]);
 70         }
 71         for (int i = 0; i < n; i++) {
 72             for (int j = 0; j < m; j++) slack[j] = inf;
 73             while (1) {
 74                 memset(S, false, sizeof(S));
 75                 memset(T, false, sizeof(T));
 76                 if (dfs(i)) break;
 77                 else update();
 78             }
 79         }
 80         int ans = 0;
 81         for (int i = 0; i < n; i++) {
 82             ans += g[i][right[i]];
 83         }
 84         return ans;
 85     }
 86 }kmm;
 87
 88 int n, m;
 89 char map[N][N];
 90 int g[N][N];
 91
 92 struct node{
 93     int x, y;
 94     node(){}
 95     node(int a,int b){
 96         x=a;
 97         y=b;
 98     }
 99 }a[N], b[N];
100
101 main()
102 {
103     int i, j, k;
104     int nx, ny;
105     while(scanf("%d %d",&n,&m)==2){
106         if(n==0&&m==0) break;
107
108         for(i=0;i<n;i++) scanf("%s",map[i]);
109         nx=ny=0;
110         memset(g,0,sizeof(g));
111         for(i=0;i<n;i++){
112             for(j=0;j<m;j++){
113                 if(map[i][j]==‘m‘) a[nx++]=node(i,j);
114                 if(map[i][j]==‘H‘) b[ny++]=node(i,j);
115             }
116         }
117         kmm.init(nx,ny);
118         for(i=0;i<nx;i++){
119             for(j=0;j<ny;j++){
120                 kmm.add_Edge(i,j,-(abs(a[i].x-b[j].x)+abs(a[i].y-b[j].y)));
121             }
122         }
123         printf("%d\n",-kmm.km());
124     }
125 }
时间: 2024-11-05 16:39:53

HDU 1533 KM算法(权值最小的最佳匹配)的相关文章

hdu 4862 KM算法 最小K路径覆盖的模型

http://acm.hdu.edu.cn/showproblem.php?pid=4862 选t<=k次,t条路要经过所有的点一次并且仅仅一次, 建图是问题: 我自己最初就把n*m 个点分别放入X集合以及Y集合,再求最优匹配,然后连样例都过不了,而且其实当时解释不了什么情况下不能得到结果,因为k此这个条件相当于没用上... 建图方法: 1.X集合和Y集合都放入n*m+k个点,X中前n*m个点和Y中前n*m个点之间,如果格子里的值相等,权就是(收益-耗费),不等就是(-耗费),因为要的是最大收益

HDU 4738 --Caocao&#39;s Bridges 【无向图边双联通 &amp;&amp; 求权值最小的桥 &amp;&amp; 模板】

Caocao's Bridges Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2641    Accepted Submission(s): 855 Problem Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. B

hdu Caocao&#39;s Bridges(无向图边双连通分量,找出权值最小的桥)

1 /* 2 题意:给出一个无向图,去掉一条权值最小边,使这个无向图不再连同! 3 4 tm太坑了... 5 1,如果这个无向图开始就是一个非连通图,直接输出0 6 2,重边(两个节点存在多条边, 权值不一样) 7 3,如果找到了桥的最小权值为0,也就是桥上的士兵数为0,那么还是要最少派一个 8 士兵过去炸掉桥! 9 10 思路:假设每两个节点最多只有一条边进行相连! 11 进行tarjan算法,如果该算法调用了超过2次,说明这个原图就是不连通的! 12 否则在tarjan算法中将桥存起来!然后

二叉树权值最大的叶子节点到权值最小的叶子节点的距离

有一棵二叉树,树上每个点标有权值,权值各不相同,请设计一个算法算出权值最大的叶节点到权值最小的叶节点的距离.二叉树每条边的距离为1,一个节点经过多少条边到达另一个节点为这两个节点之间的距离. 给定二叉树的根节点root,请返回所求距离. 真是醉了,看漏了叶子节点. 代码: 1 import java.util.*; 2 3 /* 4 public class TreeNode { 5 int val = 0; 6 TreeNode left = null; 7 TreeNode right =

hdu-4738.Caocao&#39;s Bridges(图中权值最小的桥)

Caocao's Bridges Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10933    Accepted Submission(s): 3065 Problem Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi.

UVA 548.Tree-fgets()函数读入字符串+二叉树(中序+后序遍历还原二叉树)+DFS or BFS(二叉树路径最小值并且相同路径值叶子节点权值最小)

Tree UVA - 548 题意就是多次读入两个序列,第一个是中序遍历的,第二个是后序遍历的.还原二叉树,然后从根节点走到叶子节点,找路径权值和最小的,如果有相同权值的就找叶子节点权值最小的. 最后输出来叶子节点. 一开始写的时候是用gets读入的,报CE, 要用fgets写,关于fgets(),传送门: fgets函数及其用法,C语言fgets函数详解 一开始用bfs过的,后来发现,好多人都是dfs过的,又写了一下dfs... 代码: 1 //二叉树的中序和后序遍历还原树并输出最短路径的叶子

[ACM] HDU 1533 Going Home (二分图最小权匹配,KM算法)

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2963    Accepted Submission(s): 1492 Problem Description On a grid map there are n little men and n houses. In each unit time, every

hdoj 3435 A new Graph Game 【无向图判断权值最小哈密顿环】【KM算法】

A new Graph Game Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1934    Accepted Submission(s): 827 Problem Description An undirected graph is a graph in which the nodes are connected by undir

hdu 3488(KM算法||最小费用最大流)

Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 2925    Accepted Submission(s): 1407 Problem Description In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000