hdu5093 Battle ships 二分图匹配

Description

Dear contestant, now you are an excellent navy commander, who is responsible of a tough mission currently. 

Your fleet unfortunately encountered an enemy fleet near the South Pole where the geographical conditions are negative for both sides. The floating ice and iceberg blocks battleships move which leads to this unexpected engagement highly dangerous, unpredictable and incontrollable. 

But, fortunately, as an experienced navy commander, you are able to take opportunity to embattle the ships to maximize the utility of cannons on the battleships before the engagement. 

The target is, arrange as many battleships as you can in the map. However, there are three rules so that you cannot do that arbitrary: 

A battleship cannot lay on floating ice 
A battleship cannot be placed on an iceberg 

Two battleships cannot be arranged in the same row or column, unless one or more icebergs are in the middle of them. 

Input

There is only one integer T (0<T<12) at the beginning line, which means following T test cases. 

For each test case, two integers m and n (1 <= m, n <= 50) are at the first line, represents the number of rows and columns of the battlefield map respectively. Following m lines contains n characters iteratively, each character belongs to one of ‘#’, ‘*’, ‘o’, that symbolize iceberg, ordinary sea and floating ice.

Output

For each case, output just one line, contains a single integer which represents the maximal possible number of battleships can be arranged.

题意:给定一个MxN大小的图,有3种点,冰山、浮冰、海。现在希望能在图中放置尽可能多的船。船的四个方向上不能有其他的船,除非有冰山阻隔。

比赛的时候第一眼以为是状压dp,但是状压很显然是不对劲的,直接暴力搜又好像不行(貌似学长搜索搞过了,他的具体方法没太看懂orz)

这题标准解法是二分图找最大匹配,嘛 找最大匹配直接匈牙利总归是没问题的,但是真的,就算我做完这道题了,以后再见到类似的题我都不一定能想到是二分图

好题 真的好题

建图的方法:因为一条横和一条竖的方向上如果没有冰山,那就只能放一个船,所以我们扫两遍图,比如将一行被冰山隔开且包含海水的连续区域叫做“块”。
那就是横块和竖块分别为二分图的两个部分,如果两个块之间有交叉,那就在两个块中间连一条边,然后对生成的图求最大匹配即可。

理解很好理解,因为只有横块和竖块相交的点可以放置,也就是两点连通,才可以在那里放船,同时因为相同的块不能被使用两次(题意),可知答案就是最大匹配

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
char mp[105][105];
int girl[1005];
int xs[105][105],ys[105][105];
bool used[1005];
vector<int> line[1005];
int sumx,sumy;
int n,m;
int dfs(int x) //匈牙利算法
{
	for(int j=0;j<line[x].size();j++) //邻接矩阵超时,改为邻接表
	{
		int i=line[x][j];
		if(!used[i])
		{
			used[i]=1;
			if(girl[i]==-1||dfs(girl[i]))
			{
				girl[i]=x;
				return 1;
			}
		}
	}
	return 0;
}
void setColumnRow()  //建立二分图
{
	sumx=0;
	for(int i=0;i<n;i++) //找横向点
	{
		bool flag=0;
		for(int j=0;j<m;j++)
		{
			if(mp[i][j]=='*')
			{
				if(!flag) ++sumx;
					xs[i][j]=sumx;
					flag=1;
			}
			else if(mp[i][j]=='#') flag=0;
		}
	}
	sumy=0;
	for(int j=0;j<m;j++) //纵向点
	{
		bool flag=0;
		for(int i=0;i<n;i++)
		{
			if(mp[i][j]=='*')
			{
				if(!flag) ++sumy;
				flag=1;
				ys[i][j]=sumy;
			}
			else if(mp[i][j]=='#') flag=0;
		}
	}
	for(int i=0;i<=sumx;i++) line[i].clear();
	for(int i=0;i<n;i++) //连边
	{
		for(int j=0;j<m;j++)
		{
			int u=xs[i][j];
			int v=ys[i][j];
			if(u&&v)
			{
				line[u].push_back(v);
			}
		}
	}
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		memset(girl,-1,sizeof(girl));
		//memset(line,0,sizeof(line));
		memset(xs,0,sizeof(xs));
		memset(ys,0,sizeof(ys));
		scanf("%d %d\n",&n,&m);
		for(int i=0;i<n;i++)
			scanf("%s",mp[i]);
		setColumnRow();
		//printf("%d %dfdfa\n",sumx,sumy);
		int ans=0;
		for(int i=1;i<=sumx;i++)
		{
			memset(used,0,sizeof(used));
			ans+=dfs(i);
		}
		printf("%d\n",ans);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值