HDU - 1045 -- Fire Net【二分图最大匹配数 + 思维】

题意

给定一个边长为n的方形地图,我们的目标是在一个城市中放置尽可能多的碉堡,这样两个碉堡就不会互相摧毁。堡垒的配置是合法的,前提是在地图上没有两个堡垒在同一水平行或垂直列上,除非至少有一堵墙将它们分开。在这个问题上,我们将考虑小广场城市(最多4x4),其中包含的墙壁,子弹无法通过 X代表墙壁,.代表可放置。

思路

本题最主要是怎样转化为求最大匹配数问题,对行与X的分区进行编号,对列与Y的分区进去编号,然后行的第一个分区,我们可以任意填一个碉堡,这就相当于是进行匹配(行集合与列集合的编号进行匹配),然后找一个最大匹配数即可。

AC代码
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define IOS ios::sync_with_stdio(false)
const int maxn = 20;
char mp[6][6];
int line[maxn][maxn], result[maxn], used[maxn], x[6][6], y[6][6];
int C, R, n;//C表示列的编号,R代表行的编号。 
void init(){
	memset(line, 0, sizeof(line));
	memset(result, 0, sizeof(result));
	memset(used, 0, sizeof(used));
	memset(x, 0, sizeof(x));
	memset(y, 0, sizeof(y));
}
bool found(int u){
	for (int i = 1; i <= C; ++i){
		if (line[u][i] && !used[i]){
			used[i] = 1;
			if (result[i] == 0 || found(result[i])){
				result[i] = u;
				return true;
			}
		}
	}
	return false;
}
int hungary(){
	int ans = 0;
	for (int i = 1; i <= R; ++i){
		memset(used, 0, sizeof(used));
		if (found(i))	ans++;
	}
	return ans;
} 
void cal(){
	C = 0, R = 0;
	for (int i = 0; i < n; ++i){
		for (int j = 0; j < n; ++j){
			if (mp[i][j] == '.'){
				R++;
				while (mp[i][j] == '.'){
					x[i][j] = R;
					j++;
				}
			}
		}
	}
	for (int i = 0; i < n; ++i){
		for (int j = 0; j < n; ++j){
			if (mp[j][i] == '.'){
				C++;
				while (mp[j][i] == '.'){
					y[j][i] = C;
					j++;
				}
			}
		}
	}
}
void solve(){
	while (scanf("%d", &n), n){
		init();
		for (int i = 0; i < n; ++i){
			scanf("%s", &mp[i]);
		}
		cal();
		for (int i = 0; i < n; ++i){
			for (int j = 0; j < n; ++j){
				if (mp[i][j] == '.'){
					line[x[i][j]][y[i][j]] = 1;
				}
			}
		}
		printf("%d\n", hungary());
	}
}
int main(){
	solve();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

星空皓月

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

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

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

打赏作者

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

抵扣说明:

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

余额充值