#include<stdio.h>
#include<string.h>
int n,m,I;
int dp[105][105][105],s[105],ss[105];
int max(int a,int b)
{
return a>b?a:b;
}
int check(int date)
{
if(date&date<<1)//判断是否有两个1相邻
return 0;
if(date&date<<2)//判断是否有两个1相间
return 0;
return 1;
}
int count(int date)
{
int ans=0;
while(date!=0)
{
if((date&1)==1)//判断有几个1;
ans++;
date/=2;
}
return ans;
}
void init()
{
int i;
for(i=0; i<(1<<m); i++)//判断0到1<<m的范围内所有可能放的情况即不管是否与地图矛盾
if(check(i))//只要放了炮这两个炮在同一行攻击不到的话就存到s数组内
{
s[I]=i;
ss[I++]=count(i);//count(i)表示不管地图的情况下在一行中的状态为i是的跑的个数即1的个数存放到ss[]数组内
}
}
int main()
{
int map[105],i,j,k,r,t;
char c;
scanf("%d",&t);
while(t--)
{
memset(map,0,sizeof(map));//map数组存放的是每一行的压缩状态
memset(dp,-1,sizeof(dp));//dp[i][j][k] i表示当前行j表示当前行的状态,k表示上一行的状态
scanf("%d%d",&n,&m);
if(m==0&&n==0)
{
printf("0\n");
continue;
}
for(i=0; i<n; i++)//如图中第二行,m=4,i=1,map[1]=0,当j= 2时c=H,1<<(m-j-1)为2,2|map[1]=2;
{ //当j=3时1<<(m-j-1)为1,这时map[1]=2,map[1]|1相当于1|2等于3,map[1]z最终结果为3,二级制为11,
getchar();//用1表示不能放,就把这一行的状态压缩成3
for(j=0; j<m; j++)
{
scanf("%c",&c);
if(c=='H')
map[i]=map[i]|(1<<(m-j-1));
}
}
I=0;
init();
for(i=0; i<I; i++)
{
if((s[i]&map[0])==0)//判断是否与地图矛盾
dp[0][i][0]=ss[i];
}
for(i=0; i<I; i++)
{
if((s[i]&map[1])==0)//判断是否与地图矛盾
{
for(j=0; j<I; j++)
if((s[i]&s[j])==0)//判断是否与上一行矛盾
dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+ss[i]);
}
}
for(r=2; r<n; r++)//r表示行
{
for(i=0; i<I; i++)//第r行的状态
if((s[i]&map[r])==0)//第r行的状态是否与地图矛盾
{
for(j=0; j<I; j++)//第r-1行的状态
if((s[j]&map[r-1])==0&&(s[i]&s[j])==0)//第r-1行的状态是否与地图矛盾且是否与r行的状态矛盾
{
for(k=0; k<I; k++)//第r-2行的状态
if((s[k]&map[r-2])==0&&(s[k]&s[i])==0)//是否与地图矛盾且判断是否与第r行的状态矛盾
dp[r][i][j]=max(dp[r][i][j],dp[r-1][j][k]+ss[i]);
}
}
}
int ans=0;
for(i=0; i<I; i++)//找出最后一行的状态中最大的能放炮的个数
for(j=0; j<I; j++)
if(dp[n-1][i][j]>ans)
ans=dp[n-1][i][j];
printf("%d\n",ans);
}
return 0;
}