总结:题目是求最小路径覆盖,
无向二分图的最小路径覆盖 = 顶点数 – 最大二分匹配数
#include <stdio.h>
#include <vector>
#include <string.h>
using namespace std;
const int N = 1005;
const int M = 2e3;
vector<int>G[N];
int n,g[N][N],m;
int pre[N],vis[N];
char s[N];
void fun(){
int b[4][2]={1,0,0,1,-1,0,0,-1};
for(int i = 0;i < N;i++){
G[i].clear();
}
for(int i = 0;i < n;i++){
for(int j = 0;j < m;j++){
if(g[i][j]){
for(int k = 0;k < 4;k++){
int x = i+b[k][0];
int y = j+b[k][1];
if(x>=0&&x<n&&y>=0&&y<m&&g[x][y]){
G[g[i][j]].push_back(g[x][y]);
}
}
}
}
}
}
bool dfs(int x){
for(int i = 0;i < G[x].size();i++){
int y = G[x][i];
if(!vis[y]){
vis[y] = 1;
if(!pre[y] || dfs(pre[y])){
pre[y] = x;
return true;
}
}
}
return false;
}
void solve(){
int cnt = 0;
scanf("%d%d",&n,&m);
memset(g,0,sizeof g);
for(int i = 0;i < n;i++){
scanf("%s",s);
for(int j = 0;j < m;j++){
if(s[j] == '*') g[i][j] = ++cnt;
}
}
fun();
int ans = 0;
memset(pre,0,sizeof pre);
for(int i = 1;i <= cnt;i++){
memset(vis,0,sizeof vis);
if(dfs(i)) ans++;
}
printf("%d\n",cnt-ans/2);
}
int main(){
int k;
scanf("%d",&k);
for(int i = 1;i <= k;i++){
solve();
}
return 0;
}