Skip to main content
  1. Posts/

hdu 1533 Going Home (二分图最佳匹配,KM算法)

·3 mins
Note: This article is available in Chinese only. 本文暂无英文版本。 View original

hdu 1533 题目链接

题意:给出一个n*m的maze,其中包含不超过一个人(用m表示),以及和人数相等的房子(用H表示),其他都是‘.’,表示可以经过的路径。人向一个方向移动花费代价1.问每个人都回到一个房子里的最小代价是多少。ps:每个格子是无限大的,也就是所有人可以同时踩在一个格子里。以及:路过一个房子可以不住,而只是“经过”。

思路:有了那两个条件,这题就是赤裸的二分图最优匹配了。建图也很easy.可以预处理下w,就是两点的哈密顿距离.

需要注意的是这道题求的是最小权值。那么做法就是将w取负,然后答案再次取负即可

(还有其他方法处理,不过这种最easy应该?)

(不过要保证初始化某些数组的时候要比所有的值小,所以不能是0,而应该是-inf)

以及:初始化数组为-inf的方法,可以memset(lx,0xc0,sizeof(lx));

这样得到的-inf只和inf的绝对值差1,好评如潮。

0xc0,0xc0,0xc0,重要的常数说三遍

哦还有,不要忘记在每次find的时候记录X集合中的点,这是比hungary算法的find里多的一个步骤,并且是容易忘记的。。。

  1/* ***********************************************
  2Author :111qqz
  3Created Time :2016年06月01日 星期三 16时45分41秒
  4File Name :code/hdu/1533.cpp
  5************************************************ */
  6
  7#include <cstdio>
  8#include <cstring>
  9#include <iostream>
 10#include <algorithm>
 11#include <vector>
 12#include <queue>
 13#include <set>
 14#include <map>
 15#include <string>
 16#include <cmath>
 17#include <cstdlib>
 18#include <ctime>
 19#define fst first
 20#define sec second
 21#define lson l,m,rt<<1
 22#define rson m+1,r,rt<<1|1
 23#define ms(a,x) memset(a,x,sizeof(a))
 24typedef long long LL;
 25#define pi pair < int ,int >
 26#define MP make_pair
 27
 28using namespace std;
 29const double eps = 1E-8;
 30const int dx4[4]={1,0,0,-1};
 31const int dy4[4]={0,-1,1,0};
 32const int inf = 0x3f3f3f3f;
 33const int N=105;
 34int n,m;
 35char maze[N][N];
 36int tot1,tot2;
 37int w[N][N];
 38int link[N];
 39bool visx[N],visy[N];
 40int lx[N],ly[N];
 41int slk[N];
 42struct point
 43{
 44    int x,y;
 45
 46    point(){}
 47    point(int _x,int _y):
 48	x(_x),y(_y){};
 49
 50    int dis(point b)
 51    {
 52	int res;
 53	res = abs(x-b.x)+abs(y-b.y);
 54	return -res;
 55    }
 56}p1[N*N],p2[N*N];
 57
 58void init()
 59{
 60    tot1 = tot2 = 0 ;
 61    ms(w,0xc0); //初始化为负无穷。。。0xc0这个数吼啊。。。和inf的0x3f的绝对值就差1.
 62   // cout<<"-inf:"<<w[1][1]<<endl;
 63   // cout<<"inf:"<<inf<<endl;
 64}
 65
 66bool find(int u)
 67{
 68
 69    visx[u] = true; //不要忘记标记X集合中找过增广路的点。
 70    for ( int v = 1 ; v <= tot2 ; v++)
 71    {
 72	if (visy[v]) continue;
 73	int tmp = lx[u] + ly[v] - w[u][v];
 74	if (tmp==0)
 75	{
 76	    visy[v] = true;
 77
 78	    if (link[v]==-1||find(link[v]))
 79	    {
 80		link[v] = u;
 81		return true;
 82	    }
 83	}
 84	else
 85	    if (tmp<slk[v]) slk[v] = tmp ;
 86    }
 87    return false;
 88}
 89
 90int KM()
 91{
 92    ms(lx,0xc0); //因为所有的权值都是负的(?,所以初始化不能为0而是负无穷。
 93    ms(ly,0);
 94    ms(link,-1);
 95
 96    for ( int i = 1 ; i <= tot1 ; i ++)
 97	for ( int j = 1 ; j <= tot2 ; j++)
 98	    lx[i] = max(w[i][j],lx[i]);
 99
100 //   cout<<"tot1:"<<tot1<<" tot2:"<<tot2<<endl;
101
102 //   for ( int i = 1 ; i <= tot1 ; i ++) cout<<"lx[i]:"<<lx[i]<<" ly[i]:"<<ly[i]<<endl;
103    for ( int i = 1 ; i <= tot1 ; i++)
104    {
105	ms(slk,0x3f);
106
107	while (1)
108	{
109	    ms(visx,false);
110	    ms(visy,false);
111
112	    if (find(i)) break;
113
114	    int d = inf;
115	    for ( int j = 1 ; j <= tot1 ; j++)
116	    {
117		if (!visy[j]&&slk[j]<d) d = slk[j];
118	    }
119
120	    for ( int j = 1 ; j <= tot1 ; j++) if (visx[j]) lx[j]-=d;
121	    for ( int j = 1 ; j <= tot2 ; j++) if (visy[j]) ly[j]+=d;else slk[j]-=d;
122	}
123    }
124
125
126    int res = 0 ;
127
128    for ( int i = 1 ; i <= tot1 ; i ++)
129	if (link[i]>-1) res += w[link[i]][i];
130
131    return -res;
132
133
134}
135int main()
136{
137	#ifndef  ONLINE_JUDGE
138	freopen("code/in.txt","r",stdin);
139  #endif
140	while (scanf("%d%d",&n,&m)!=EOF)
141	{
142	    if (n==0&&m==0) break;
143
144	    init();
145	    for ( int i = 0 ; i < n ; i++) scanf("%s",maze[i]);
146
147	    for ( int i = 0 ; i < n ; i++)
148		for ( int j = 0 ; j < m ; j++)
149		    if (maze[i][j]=='m') p1[++tot1] = point(i,j);
150		    else if (maze[i][j]=='H')p2[++tot2] = point(i,j);
151
152	    for ( int i = 1 ; i <= tot1 ; i ++)
153		for ( int j = 1; j <= tot2 ; j++)
154		    w[i][j] = p1[i].dis(p2[j]);
155
156	  //  cout<<"wwwwwwwwwwwwW?????"<<endl;
157	    int ans = KM();
158	  //  cout<<"kkkkkkkkkkkkkkkkk"<<endl;
159	    printf("%d\n",ans);
160
161	}
162
163  #ifndef ONLINE_JUDGE
164  fclose(stdin);
165  #endif
166    return 0;
167}

Related

hdu 2255 奔小康赚大钱 (二分图最佳匹配,KM算法模板题)

·8 mins
hdu 2255 题目链接 题意:传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。 这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。 另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万.(当然是在他们的经济范围内).现在这个问题就是村领导怎样分配房子才能使收入最大.(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的).

poj 1719 Shooting Contest (匈牙利算法)

·2 mins
poj1719题目链接 题意:射箭比赛,靶子是一个n*m的网格。网格的特点是没列只有两个白色,剩下的全是黑色。一共射m次,每列射一次,要求每行都射到至少一次才算合法,问是否有合法射法,如果有输出一组解。

hdu 4185 Oil Skimming (二分图最大匹配,匈牙利算法)

·2 mins
hdu 4185题目链接 题意:给出一个nn的字符maze,‘.’代表水,‘#’代表油田。 挖油的机器一次会挖两个相邻方块。要求是必须两块必须都是油,不然会有杂质。问最多能挖多少次。 思路:和那道用12的小矩形块填充是一个思路。根据奇偶性对点标号,然后建图,匈牙利,2A. 第一遍是dfs写错了一个变量QAQ.a