【二分图+最大匹配+有难度】poj 2226 Muddy Fields

/* THE PROGRAM IS MADE BY PYY */
/*----------------------------------------------------------------------------//
	Copyright (c) 2011 panyanyany All rights reserved.

	URL   : http://poj.org/problem?id=2226
	Name  : 2226 Muddy Fields

	Date  : Sunday, December 04, 2011
	Time Stage : two hours

	Result: 
9625653	panyanyany
2226
Accepted	9168K	125MS	C++

Test Data :

Review :
先附上大牛的解题报告,以示尊敬和感谢:
http://blog.csdn.net/weiguang_123/article/details/6923711
http://blog.csdn.net/acmj1991/article/details/6825090

这题比较纠结,虽然跟 poj 3041 Asteroids 有点像,但毕竟还是很不相同的。
起码一开始没有思路,看了人家的解题报告,也是琢磨了好久的。

具体思路:
	因为这是一个矩阵,那么就有两种方法可以适用于任何情况。第一种是把矩阵划分为
r 行,然后按行来铺木板,这样不论有多少人泥地,怎么分布,都可以铺上去。第二种是把
矩阵划分为 c 列,然后按列来铺木板。
	这两种方法的特点是不考虑最优化。

	如果要考虑最优化呢?可以把按行划分的所有木板编号,为 Y 点集,把按列划分的
所有木板编号,为 X 点集。
	那么,怎么样使 x 和 y 点集连线呢?可以先对被同一块木板覆盖的方格都统一编号
为木板的编号。不过,同一个方格必然会被两个不同的木板覆盖,所以就要有两套图,
第一套只记录以行划分的编号,第二套只记录以列划分的编号。如此一来,同一点的两个
不同编号(比如x1, y1),就代表 X 点集中 点x1 与 Y 点集中 点y1 有一条公共边。
	然后再二分匹配求最大匹配即可。

	最后,要注意数组,不能开太大,否则MLE,太小了则WA
//----------------------------------------------------------------------------*/

#include <stdio.h>
#include <string.h>

#define MAXSIZE		55*55

int		r, c, xCnt, yCnt ;
int		link[MAXSIZE] ;
bool	cover[MAXSIZE] ;
char	map[55][55] ;
bool	graph[MAXSIZE][MAXSIZE] ;
int		mapx[55][55], mapy[55][55] ;

bool find (int cur)
{
	int i ;
	for (i = 1 ; i <= xCnt ; ++i)
	{
		if (cover[i] == false && graph[cur][i] == true)
		{
			cover[i] = true ;
			if (link[i] == 0 || find (link[i]))
			{
				link[i] = cur ;
				return true ;
			}
		}
	}
	return false ;
}

int getSum ()
{
	int i ;
	int sum ;
	sum = 0 ;

	memset (link, 0, sizeof (link)) ;
	for (i = 1 ; i <= yCnt ; ++i)
	{
		memset (cover, 0, sizeof (cover)) ;
		sum += find (i) ;
	}
	return sum ;
}

int main ()
{
	int i, j ;

	while (~scanf ("%d%d", &r, &c))
	{
		for (i = 0 ; i < r ; ++i)
			scanf ("%s", map[i]) ;

		memset (mapx, 0, sizeof (mapx)) ;
		memset (mapy, 0, sizeof (mapy)) ;
		yCnt = 0 ;
		for (i = 0 ; i < r ; ++i)
			for (j = 0 ; j < c ; ++j)
				if (map[i][j] == '*')
				{
					++yCnt ;
					while (j < c && map[i][j] == '*')
					{
						mapy[i][j] = yCnt ;
						++j ;
					}
				}
		xCnt = 0 ;
		for (j = 0 ; j < c ; ++j)
			for (i = 0 ; i < r ; ++i)
				if (map[i][j] == '*')
				{
					++xCnt ;
					while (i < r && map[i][j] == '*')
					{
						mapx[i][j] = xCnt ;
						++i ;
					}
				}

		memset (graph, 0, sizeof (graph)) ;
		for (i = 0 ; i < r ; ++i)
			for (j = 0 ; j < c ; ++j)
				graph[mapy[i][j]][mapx[i][j]] = 1 ;

		printf ("%d\n", getSum ()) ;
	}
	return 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写代码的安徒生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值