题意
给定一个边长为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;
}