【HDU 1533】 Going Home (KM)

Going Home

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

【题意】

  

给你一个类似这样的图

...H....

...H....

...H....

mmmHmmmm

...H....

...H....

...H....

问所有H移动到所有m上花费最少的步数

【分析】

  这题题解都是费用流,可能不卡费用流。

  我打的是n^3 KM,不过求的是最小边权的最佳匹配,所以把边权先取反然后再做。

  记得一开始初始化lx的时候是-INF 不是0,有负边。

代码如下:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 110
  9 #define Maxm 10010
 10 #define INF 0xfffffff
 11
 12 struct node
 13 {
 14     int x,y,c,next;
 15 }t[Maxm];int len;
 16 int first[Maxn];
 17
 18 int mymin(int x,int y) {return x<y?x:y;}
 19 int mymax(int x,int y) {return x>y?x:y;}
 20 int myabs(int x) {return x>0?x:-x;}
 21
 22 int hx[Maxn],hy[Maxn],mx[Maxn],my[Maxn];
 23 int fn;
 24
 25 void ins(int x,int y,int c)
 26 {
 27     t[++len].x=x;t[len].y=y;t[len].c=-c;
 28     t[len].next=first[x];first[x]=len;
 29 }
 30
 31 int lx[Maxn],ly[Maxn];
 32 bool visx[Maxn],visy[Maxn];
 33 int slack[Maxn],match[Maxn];
 34
 35 char s[Maxn];
 36
 37 bool ffind(int x)
 38 {
 39     visx[x]=1;
 40     for(int i=first[x];i;i=t[i].next) if(!visy[t[i].y])
 41     {
 42         int y=t[i].y;
 43         if(lx[x]+ly[y]==t[i].c)
 44         {
 45             visy[y]=1;
 46             if(!match[y]||ffind(match[y]))
 47             {
 48                 match[y]=x;
 49                 return 1;
 50             }
 51         }
 52         else slack[y]=mymin(slack[y],lx[x]+ly[y]-t[i].c);
 53     }
 54     return 0;
 55 }
 56
 57 void solve()
 58 {
 59     memset(match,0,sizeof(match));
 60     memset(ly,0,sizeof(ly));
 61     // memset(lx,0,sizeof(lx));
 62     for(int i=1;i<=fn;i++)
 63     {
 64         lx[i]=-INF;
 65         for(int j=first[i];j;j=t[j].next) lx[i]=mymax(lx[i],t[j].c);
 66     }
 67
 68     for(int i=1;i<=fn;i++)
 69     {
 70         for(int j=1;j<=fn;j++)
 71             slack[j]=INF;
 72         while(1)
 73         {
 74             memset(visx,0,sizeof(visx));
 75             memset(visy,0,sizeof(visy));
 76             if(ffind(i)) break;
 77
 78             int delta=INF;
 79             for(int j=1;j<=fn;j++) if(!visy[j])
 80               delta=mymin(delta,slack[j]);
 81
 82             if(delta==INF) return ;
 83
 84             for(int j=1;j<=fn;j++)
 85             {
 86                 if(visx[j]) lx[j]-=delta;
 87                 if(visy[j]) ly[j]+=delta;
 88                 else slack[j]-=delta;
 89             }
 90         }
 91     }
 92 }
 93
 94 int main()
 95 {
 96     int n,m;
 97     while(1)
 98     {
 99         scanf("%d%d",&n,&m);
100         if(n==0&&m==0) break;
101         hx[0]=mx[0]=0;
102         for(int i=1;i<=n;i++)
103         {
104             scanf("%s",s);
105             for(int j=0;j<m;j++)
106             {
107                 if(s[j]==‘H‘) hx[++hx[0]]=i,hy[hx[0]]=j+1;
108                 else if(s[j]==‘m‘) mx[++mx[0]]=i,my[mx[0]]=j+1;
109             }
110         }
111         len=0;
112         memset(first,0,sizeof(first));
113         for(int i=1;i<=hx[0];i++)
114          for(int j=1;j<=mx[0];j++)
115             ins(i,j,myabs(hx[i]-mx[j])+myabs(hy[i]-my[j]));
116         fn=hx[0];
117         solve();
118         int ans=0;
119         for(int i=1;i<=fn;i++) ans+=lx[i]+ly[i];
120         printf("%d\n",-ans);
121     }
122     return 0;
123 }

HDU 1533

容易打错的地方是visx 和 visy 的标记。

表示的是是否为增广路上的点,前提当然是他也在相等子图上。

2016-10-27 09:45:40

时间: 2024-10-13 07:42:45

【HDU 1533】 Going Home (KM)的相关文章

【HDU 3400】Line belt(三分法)

题目链接 题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=3400 题意 有两条传送带AB和CD,移动速度分别为p,q. 除了传送带的其他区域移动速度为r,问A到D最短时间. 题目分析 在AB上找一点E,在CD上找一点F. 使得A->E->F->D时间最短. 数学思路 时间 time = |AE|/p + |EF|/r + |FD|/q. (|AE|为线段AE的长度.) 未知量有E的位置和F的位置,由于确定在AB和CD上,所以只需要两个未知量

【HDU 3640】I, zombie (二分)

传送门 题目描述 The "endless" model in "I, zombie" of "Plants vs. Zombies" is my favourite.The aim of the game is to put down the zombies most reasonable in the right-most , to eat the brain protected by Plants in the left-most. To

【HDU 5839】Special Tetrahedron(计算几何)

空间的200个点,求出至少四边相等,且其余两边必须不相邻的四面体的个数. 用map记录距离点i为d的点有几个,这样来优化暴力的四重循环. 别人的做法是枚举两点的中垂面上的点,再把到中点距离相等的点找出来,n^3的样子. 还要注意四个点共面的情况. 共面判断就是用叉乘计算出ijk三点所在面的法向量,然后判断il向量是否和法向量垂直,是则共面. #include <cstdio> #include <cstring> #include <algorithm> #includ

【HDU 4763】Theme Section(KMP)

这题数据水的一B,直接暴力都可以过. 比赛的时候暴力过的,回头按照正法做了一发. 匹配的时候 失配函数 其实就是前缀 后缀的匹配长度,之后就是乱搞了. KMP的题可能不会很直接的出,但是KMP的思想经常渗透在很多题目里面,最近需要多练习一下. #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1000005; int _next[max

【HDU 5091】Beam Cannon(扫描线)

按照x轴建树,求线段树的区间最值. 模型转化就是: 矩阵最大交 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define lson (pos<<1) #define rson (pos<<1|1) const int ADD = 25555; const int maxn = 80005; int n,w,h,cnt; struct Se

【HDU 4445】Crazy Tank(暴力)

高中物理斜抛运动,简单分析一下角度固定下来则可以计算每个cannonball的降落坐标lnd. 因此暴力计算不同角度下的结果. #include <cstdio> #include "cmath" #include "algorithm" #define ll long long #define dd double #define N 205 #define g 9.8 #define eps 1e-6 const dd pi=acos(-1.0); l

【hdu 5918】Sequence I(KMP)

给定两个数字序列,求a序列中每隔p个构成的p+1个序列中共能匹配多少个b序列. 例如1 1 2 2 3 3 每隔1个的序列有两个1 2 3 kmp,匹配时每次主串往前p个,枚举1到p为起点. 题目 #include<bits/stdc++.h> #define N 1000005 int t,n,m,p; int nex[N]; int a[N],b[N]; using namespace std; void getNext(){ int i=0,k=-1; nex[0]=k; while(b

【HDU 5335】Walk Out(BFS)

这道题卡时间卡的比较紧. 一开始直接BFS 毫无疑问的超时,之后想到根据BFS的常规优化思想,去选择起始点进行遍历. 这样我们一开始先BFS一次,这次的BFS是选择出这一点为1并且从起点到这一个点,中间路径的点全为0的点. 这样选择出这个点之后,这个点到终点的路径长度就可以断定了. 之后我们把所有到终点距离最小的点放在一个容器里进行BFS. 这道题没有做出来的原因很大一部分就是对BFS的理解不够深以及该有的贪心思路没有,导致了这道题没有AC. 嗯,有句话说的对:综合是第一生产力. #includ

【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