poj3020

题目大意

一个长方形图由问*和o组成,每个1*2的小长方形,问几个小长方形可以覆盖全部的*


思路:

这提的难点在于建图,纠结了一天参考别人的建图方法总算才AC。

建图的时候应该给每个*的点都加上编号,之后用编号之间的的连接关系建立二分图。

建图的时候还应该注意如果两个点之间可以连接那么就两边都连上边,

刚开始想一次解决却发现由于图的关系挺复杂的,起点集终点集并不好判断。

如果不能把起点集终点集找准确,肯定是要吃WA的。

而建成这种双向边的形式只要把得到的匹配结果除以二就是真正的匹配结果了,原理也很简单。

每个参与匹配的点都作为一次起点和一次终点参与了匹配。而最小覆盖又等于最大匹配。

上面的匹配结果除以2是这个图真正的匹配数,而匹配数乘以2就是一个每个覆盖两个点的小长方形的总覆盖数。

剩下的*每个都要用一个小长方形覆盖。

#include<iostream>
#include<Cstdio>
#include<string>
using namespace std;

int map[500][500],  visitY[500], useY[500];
int vis[20][50];
int h, l,sum;
int dirX[] = {1, 0, 0, -1};
int dirY[] = {0, 1, -1, 0};
bool match(int n)
{
	int i;
	for(i = 1; i <= sum; i++)
	{
		if(map[n][i] == 1 && useY[i] == -1)
		{
			useY[i] = 1;
			if(visitY[i] == -1 ||  match(visitY[i]))
			{
				visitY[i] = n;
				return true;
			}
		}
	}
	return false;
}

int Find()
{
	int i, c=0, j;
	for(i = 1; i <= sum; i++)
	{
		for(j = 1; j <= sum; j++)
			useY[j] = -1;
		if(match(i))
			c++;
	}
	cout << sum - c/2 << endl;
	return 0;
}


int main()
{
	char temp;
	int i, j, k, size, x, y;
	scanf("%d", &size);
	while(size--)
	{
		scanf("%d%d", &h, &l);
		sum = 0;
		for(j = 1; j <= h; j++)
		{
			for(i = 1; i <= l; i++)
			{
				cin >> temp;
				vis[i][j] = -1;
				if(temp == '*')
					vis[i][j] = ++sum;
			}
		}
		
		for(i = 1; i <= sum; i++)
			for(j = 1; j <= sum; j++)
				map[i][j] = -1;
		
		for(j = 1; j <= h; j++)
		{
			for(i = 1; i <= l; i++)
			{
				if(vis[i][j] != -1)
				{
					for(k = 0; k < 4; k++)
					{
						x = i + dirX[k]; y = j + dirY[k];
						if(vis[x][y] != -1)
							map[vis[i][j]][vis[x][y]] = 1;
					}
				}

			}
		}
		
		for(i = 1; i <= sum; i++)
			visitY[i] = -1;
		Find();
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值