典型的二分图最大匹配的问题:
具体而言就是对里面的点分做两类,一类是横纵坐标之和是奇数的点,一类是横纵坐标之和是偶数点,只有这两类的点才能匹配,建边的原则是看它的四个方向和它本身是否是'*'号,然后答案就是所有为'*'的点减去最大匹配的值。
#include "stdio.h"
#include "string.h"
#include "math.h"
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
using namespace std;
#define MAXM 805
#define MAXN 405
#define max(a,b) a > b ? a : b
#define min(a,b) a < b ? a : b
#define abs(a) a < 0 ? a : (-a)
#define Mem(a,b) memset(a,b,sizeof(a))
int Mod = 1000000007;
double pi = acos(-1.0);
double eps = 1e-6;
typedef struct{
int f,t,w,next;
}Edge;
Edge edge[MAXM];
int head[MAXN];
char s[2][MAXN];
int kNum;
void addEdge(int f, int t, int w)
{
edge[kNum].f = f;
edge[kNum].t = t;
edge[kNum].w = w;
edge[kNum].next = head[f];
head[f] = kNum ++;
}
int T, N, M;
int cx[MAXN], cy[MAXN];
bool visit[MAXN];
int findpath(int u){
for(int k = head[u]; k != -1; k = edge[k].next){
int t = edge[k].t;
if( visit[t] ) continue;
visit[t] = true;
if( cy[t] == -1 || findpath(cy[t]) ){
cy[t] = u;
cx[u] = t;
return 1;
}
}
return 0;
}
void solve(){
Mem(cx,-1);
Mem(cy,-1);
Mem(head,-1);
kNum = 0;
int sum = 0, ans = 0;
for(int i = 0; i < N; i ++){
getchar();
scanf("%s",s[i%2]);
for(int j = 0; j < M; j ++){
if( s[i%2][j] == '*'){
sum ++;
if( i - 1 >= 0 && s[(i-1) %2][j] == '*' ){
if( ( i + j ) % 2 == 0 ){
addEdge( i * M + j, (i-1) * M + j, 0);
}
else{
addEdge( (i - 1) * M + j, i * M + j, 0);
}
}
if( j - 1 >= 0 && s[i%2][j-1] == '*' ){
if( ( i + j ) % 2 == 0 ){
addEdge( i * M + j, i * M + j - 1, 0);
}
else{
addEdge( i * M + j - 1, i * M + j, 0);
}
}
}
}
}
for(int i = 0; i < N * M; i ++){
if( ( i / M + i % M ) % 2 == 0 && head[i] != -1 && cx[i] == -1 ){
Mem(visit, false);
ans += findpath(i);
}
}
printf("%d\n",sum - ans);
}
int main()
{
// freopen("d:\\test.txt", "r", stdin);
while(cin>>T){
while( T-- ){
cin>>N>>M;
solve();
}
}
return 0;
}