题意:有一个N*N的棋盘,有可放炮台的地方和墙,X是墙,'.'可放炮台,在同一行或同一列的炮台会互相攻击,有墙的话可以隔开,问你最多可以放几架炮台。
行列匹配,有墙的话就把行或列拆分成多个行或列就好了。
链接:hdu - 1045
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 50;
int used[maxn];
int link[maxn];
int mat[maxn][maxn];
int gn, gm;
int dfs(int t) {
for(int i = 1; i <= gm; i++) {
if(!used[i] && mat[t][i]) {
used[i] = 1;
if(link[i] == -1 || dfs(link[i])) {
link[i] = t;
return 1;
}
}
}
return 0;
}
int maxmatch() {
int num = 0;
memset(link, 0xff, sizeof(link));
for(int i = 1; i <= gn; i++) {
memset(used, 0, sizeof(used));
if(dfs(i)) {
num++;
}
}
return num;
}
char s[maxn][maxn];
int x[maxn][maxn];
int y[maxn][maxn];
int main()
{
int n, m, k, t;
while(~scanf("%d", &n) && n) {
int cnt = 1;
int flag = 0;
for(int i = 0; i < n; i++) {
scanf("%s", s[i]);
for(int j = 0; j < n; j++) {
if(s[i][j] == '.') {
y[i][j] = cnt;
flag = 1;
}
else if(flag) {
flag = 0;
cnt++;
}
}
if(flag) {
cnt++;
flag = 0;
}
}
gn = cnt;
cnt = 1;
flag = 0;
for(int j = 0; j < n; j++) {
for(int i = 0; i < n; i++) {
if(s[i][j] == '.') {
x[i][j] = cnt;
flag = 1;
}
else if(flag) {
flag = 0;
cnt++;
}
}
if(flag) {
cnt++;
flag = 0;
}
}
gm = cnt;
/*for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
cout << x[i][j]<< " ";
}
cout << endl;
}
cout << endl;
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
cout << y[i][j]<< " ";
}
cout << endl;
}
cout << endl;*/
memset(mat, 0, sizeof(mat));
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(s[i][j] == '.') {
mat[x[i][j]][y[i][j]] = 1;
}
}
}
/*for(int i = 0; i <= gn; i++) {
for(int j = 0; j <= gm; j++) {
cout << mat[i][j]<< " ";
}
cout << endl;
}
cout << endl;*/
int res = maxmatch();
printf("%d\n", res);
}
return 0;
}