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

题意

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

思路

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

AC代码

#include
#include
#include
#include
#include
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;
}

你可能感兴趣的:(#,二分图,最大匹配数,#,思维题)