( ̄▽ ̄)"
//无向二分图的最小路径覆盖数=顶点总数-最大匹配数/2(最大匹配数=最小点覆盖数)
//这里最大匹配数需要除以2,因为每两个相邻的*连一条边,即<u,v>和<v,u>是一样的,所以结果多了一倍
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=405;
int uN;
char G[MAXN][MAXN];
int Hash[MAXN][MAXN];
vector<int> g[MAXN];
int link[MAXN];
bool vis[MAXN];
bool DFS(int u)
{
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!vis[v])
{
vis[v]=true;
if(link[v]==-1||DFS(link[v]))
{
link[v]=u;
return true;
}
}
}
return false;
}
int hungary()
{
int res=0;
memset(link,-1,sizeof(link));
for(int u=0;u<uN;u++)
{
memset(vis,0,sizeof(vis));
if(DFS(u)) res++;
}
return res;
}
int main()
{
int cas,tot;
scanf("%d",&cas);
while(cas--)
{
int h,w;
tot=0;
scanf("%d%d",&h,&w);
for(int i=0;i<h;i++)
{
scanf("%s",G[i]);
for(int j=0;j<w;j++)
{
if(G[i][j]=='*')
Hash[i][j]=tot++; //构建数字图
}
}
memset(g,0,sizeof(g));
for(int i=0;i<h;i++)
for(int j=0;j<w;j++)
if(G[i][j]=='*')
{
if(i>0&&G[i-1][j]=='*')
g[Hash[i][j]].push_back(Hash[i-1][j]);
if(i<h-1&&G[i+1][j]=='*')
g[Hash[i][j]].push_back(Hash[i+1][j]);
if(j>0&&G[i][j-1]=='*')
g[Hash[i][j]].push_back(Hash[i][j-1]);
if(j<w-1&&G[i][j+1]=='*')
g[Hash[i][j]].push_back(Hash[i][j+1]);
}
uN=tot;
printf("%d
",tot-hungary()/2);
}
return 0;
}