/*
    40*10的地圖,有一些'*'必須用方塊覆蓋到
    而每塊方塊只能覆蓋長度為1*2
    問最少需要的方塊數(shù)

    狀態(tài)壓縮dp,主要就是枚舉當(dāng)前行的狀態(tài)to,上一行的狀態(tài)from,由from的值去更新to的值

    骨牌覆蓋類求方案數(shù)的,一般都需要枚舉所有情況,即放、不放
    但這種求最優(yōu)值的,我一開始枚舉所有情況,導(dǎo)致超時!!
    需要人肉優(yōu)化
    比如,這里空的位置肯定不用放東西,直接下一列

    這道題,轉(zhuǎn)移時只需考慮當(dāng)前row和上一行row-1,
    對于列col 分4種情況,
    00 01 10 11
    1表示該位置是'*'
    分這4種情況:
    ①不放 狀態(tài)構(gòu)造為 to<<1 , from<<1
    ②上一行有'*'  狀態(tài)構(gòu)造為 to<<1 , from<<1|1
    ③當(dāng)前行有'*'  由于上一行沒有,就沒必要豎放了,直接橫放了,豎放不會導(dǎo)致最優(yōu)解
       然后還要考察col+1是否有'*',有的話狀態(tài)要加上去
       當(dāng)然,該位置可以不放,為了給下一行覆蓋
    ④上下行都有'*'
       不放的話,上一行就需要有覆蓋了
       橫放,上一行肯定就要被覆蓋了
       豎放,上一行可選擇被覆蓋,或者沒被覆蓋
       但選擇被覆蓋是不會導(dǎo)致最優(yōu)解的,因為橫放的時候就會考慮上一行該位置要被覆蓋了
        

    求最優(yōu)值(不是求方案),沒必要轉(zhuǎn)移時 from -> to 把一些明顯不優(yōu)的狀態(tài)from轉(zhuǎn)移到to去
    如對于'O'位置,可以放,但肯定不去放它,放了不會更優(yōu)的,所以不進入這個分支了
    分支數(shù)決定了規(guī)模,人肉優(yōu)化,不進入沒必要的分支
    但求方案數(shù)目的話,就要考慮所有情況了,放、不放之類的
*/
    
#include
<iostream>
#include
<cstring>
#include
<map>
#include
<algorithm>
#include
<stack>
#include
<queue>
#include
<cmath>
#include
<string>
#include
<cstdlib>
#include
<vector>
#include
<cstdio>
#include
<set>
#include
<list>
#include
<numeric>
#include
<cassert>

using namespace std;

const int INF = 1000000000;

char field[50][20];
int dp[50][1<<10];
int H, W;

void dfs(int row, int col , int s1 , int s2 , int num){//當(dāng)前檢查col
    /*if(col > W){
        return;
    }
*/

    
if(col >=  W){//因為可能在最后一列水平覆蓋,所以出格了
        if(col>W){//注意>>
            s1 >>= 1;
            s2 
>>= 1;
        }

        dp[row][s1] 
= min(dp[row][s1] , dp[row-1][s2] + num);
        
return;
    }

    
int code = (field[row][col] == '*')*2 + (field[row-1][col] == '*');
    
    
switch(code){
        
case 0:
            dfs(row, col
+1, s1<<1, s2<<1, num);            
            
break;
        
case 1:
            dfs(row, col
+1, s1<<1, s2<<1|1, num);//用|去覆蓋(row-1,col)跟(row-1,col)自己覆蓋效果一樣
            break;
        
case 2:
            dfs(row, col
+2, (s1<<2)|2|(field[row][col+1== '*'), (s2<<2)|(field[row-1][col+1== '*'), num+1);
            
//nothing
            dfs(row, col+1, s1<<1, s2<<1, num);
            
break;
        
case 3:
            
//nothing
            dfs(row, col+1, s1<<1, s2<<1|1, num);
            dfs(row, col
+1, s1<<1|1, s2<<1, num+1);
            
//dfs(row, col+1, s1<<1|1, s2<<1|1, num+1);  s2<<1|1在下面的狀態(tài)會考慮到的,而且下面的不會比它差 所以不用再dfs
            dfs(row, col+2, (s1<<2)|2|(field[row][col+1== '*'), (s2<<2)|2|(field[row-1][col+1== '*'), num+1);
            
break;
    }

}


int main()
{
#ifndef ONLINE_JUDGE
    freopen(
"in","r",stdin);
#endif

    
int T;
    
for(scanf("%d",&T); T-- ;){
        scanf(
"%d%d",&H,&W);
        
for(int i = 1 ; i <= H; i++){
            scanf(
"%s",field[i]);
        }
    
        
for(int row = 1 ; row <= H ; row++){
            fill(dp[row] , dp[row] 
+ (1<<W), INF);
            dfs(row,
0,0,0,0);
        }

        
int ans = INF;
        
int mask = 0;
        
for(int i = 0; i < W ; i++){
            mask 
<<= 1;
            mask 
|= (field[H][i] == '*');
        }

        
for(; mask < (1<<W);mask++){
            ans 
= min(ans, dp[H][mask]);
        }

        printf(
"%d\n",ans);
    }
    
    
return 0;
}