有一些’o’和’‘构成的图,每个可以与其四周的’‘连一条边,但是连完之后这两个‘’就称作被覆盖了,不能与其他的’‘发生交集了。 然后问用最少的边能把所有的‘’都覆盖掉
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NavigableSet;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
import java.util.SortedSet;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeSet;
public class Main {
public static void main(String[] args) throws IOException{
StreamTokenizer cin = new StreamTokenizer(new BufferedInputStream(System.in));
InputReader in = new InputReader(System.in) ;
PrintWriter out = new PrintWriter(System.out) ;
int t = in.nextInt() ;
for(int i = 0 ; i < t ; i++){
new Task().solve(in, out) ;
}
out.flush();
}
}
class Task{
static int[][] id = new int[40][10] ;
static int[][] dir = new int[][]{{-1,0},{0,-1},{1,0},{0,1}} ;
int n , m ;
char[][] grid ;
boolean can(int x , int y){
return 0 <= x && x < n && 0 <= y && y < m ;
}
public void solve(InputReader in , PrintWriter out) throws IOException{
n = in.nextInt() ;
m = in.nextInt() ;
grid = new char[n][m] ;
for(int i = 0 ; i < n ; i++) grid[i] = in.next().toCharArray() ;
int l = 0 , r = 0 ;
for(int i = 0 ; i < n ; i++){
for(int j = 0 ; j < m ; j++){
if(grid[i][j] == '*'){
if(((i+j) & 1) > 0) id[i][j] = ++l ;
else id[i][j] = ++r ;
}
}
}
MaxMatch solver = new MaxMatch(l, r) ;
for(int i = 0 ; i < n ; i++){
for(int j = 0 ; j < m ; j++){
if(grid[i][j] == '*' && ((i+j)&1) > 0){
for(int k = 0 ; k < 4 ; k++){
int x = i + dir[k][0] ;
int y = j + dir[k][1] ;
if(can(x, y) && grid[x][y] == '*') solver.add(id[i][j], id[x][y]) ;
}
}
}
}
out.println(l+r - solver.getMaxmatch() ) ;
}
}
class MaxMatch{
static final int N = 208 ;
static int[] g = new int[N] ;
static int[] next = new int[N*N] ;
static int[] ev = new int[N*N] ;
static int id ;
void add(int u , int v){
ev[id] = v ;
next[id] = g[u] ;
g[u] = id++ ;
}
int n , m ;
static int[] match = new int[N] ;
static boolean[] vis = new boolean[N] ;
MaxMatch(int n , int m){
this.n = n ;
this.m = m ;
id = 0 ;
Arrays.fill(g, 1 , n+1, -1) ;
}
boolean dfs(int u){
for(int i = g[u] ; i != -1 ; i = next[i]){
int v = ev[i] ;
if(vis[v]) continue ;
vis[v] = true ;
if(match[v] == -1 || dfs(match[v])){
match[v] = u ;
return true ;
}
}
return false ;
}
int getMaxmatch(){
Arrays.fill(match, 1 , n+1 , -1) ;
int sum = 0 ;
for(int u = 1 ; u <= n ; u++){
Arrays.fill(vis, 1 , m+1 , false) ;
if(dfs(u)) sum++ ;
}
return sum ;
}
}
class InputReader{
public BufferedReader reader;
public StringTokenizer tokenizer;
public InputReader(InputStream stream){
reader = new BufferedReader(new InputStreamReader(stream), 32768) ;
tokenizer = null ;
}
public String next(){
while(tokenizer == null || ! tokenizer.hasMoreTokens()){
try{
tokenizer = new StringTokenizer(reader.readLine());
}catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public int nextInt(){
return Integer.parseInt(next());
}
public long nextLong(){
return Long.parseLong(next());
}
public double nextDouble(){
return Double.parseDouble(next());
}
}