题意:给一个最大4*4的网格,每个格子是空地或者墙,需要你在空地上安放炮楼,炮楼的攻击范围是直线,要求炮楼不能互相攻击,问最多放多少个炮楼。
如果一行被一堵墙分成两份,那我们就把这一行当作两个小行,同理,如果一列被墙分成了两份,我们就把这一列拆成两个小列。建立二分图,左边是小行,右边是小列,有公共点的话就连一条边,然后求最大匹配即可。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
//#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <string>
#define N 150
#define ll long long
#define INF 0x7fffffff
using namespace std;
int n,ccnt,rcnt;
bool con[N][N];//用来记录小行与小列的关系。
char map[N][N];
int rec[N][N];//用来记录每个点所属的小行的编号
int match[N];
bool used[N];
bool found(int x){
for(int i=1;i<=ccnt;i++){
if(!used[i] && con[x][i]){
used[i] = 1;
if(match[i] == 0 || found(match[i])){
match[i] = x;
return 1;
}
}
}
return 0;
}
int main(){
int i,j,k;
while (scanf("%d",&n),n)
{
memset(con,0,sizeof(con));
memset(match,0,sizeof(match));
memset(rec,0,sizeof(rec));
getchar();
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
scanf("%c",&map[i][j]);
}
getchar();
}
rcnt = 0;
bool flag = 1;
for(i=1;i<=n;i++){
if(flag == 0){
flag = 1;
}
for(j=1;j<=n;j++){
if(map[i][j] == '.'){
if(flag){
rcnt++;
flag = 0;
}
rec[i][j] = rcnt;
}else{
flag = 1;
}
}
}
ccnt = 0;
for(j=1;j<=n;j++){
flag = 1;
for(i=1;i<=n;i++){
if(map[i][j] == '.'){
if(flag){
ccnt++;
flag = 0;
}
con[rec[i][j]][ccnt] = 1;
}else{
flag = 1;
}
}
}
int ans = 0;
for(i=1;i<=rcnt;i++){
memset(used,0,sizeof(used));
if(found(i)){
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}