#include #include #include #include #include #include #include #include using namespace std; const int N = 50, M = N * N; char a[N][N]; // 原始矩阵 // 链式前向星 int e[M], h[N], idx, w[M], ne[M]; void add(int a, int b, int c = 0) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } int dx[] = {-1, 0, 1, 0}; // 上右下左 int dy[] = {0, 1, 0, -1}; // 上右下左 int n, m; // n行m列 // 匈牙利算法 int st[M], match[M]; int dfs(int u) { for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; if (st[v]) continue; st[v] = 1; if (match[v] == -1 || dfs(match[v])) { match[v] = u; return 1; } } return 0; } int main() { #ifndef ONLINE_JUDGE freopen("POJ3020.in", "r", stdin); #endif int T; scanf("%d", &T); while (T--) { // 初始化链式前向星 memset(h, -1, sizeof h); idx = 0; scanf("%d %d", &n, &m); // n*m的矩阵 for (int i = 1; i <= n; i++) scanf("%s", a[i] + 1); // 使用char[],按行一次读入,快捷! int cnt = 0; // 城市个数 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { //*--代表城市,o--代表空地 // 给城市安装无线网,一个无线网最多可以覆盖两座城市,问覆盖所有城市最少要用多少无线网。 if (a[i][j] == '*') { cnt++; // 四周探测 for (int k = 0; k < 4; k++) { int tx = i + dx[k], ty = j + dy[k]; if (tx < 1 || tx > n || ty < 1 || ty > m) continue; // 城市到城市建边,无向图,尽量让无线网构建在两个城市上,这样才能省资源,要不一个城市一个无向网太费了 if (a[tx][ty] == '*') add((i - 1) * m + j, (tx - 1) * m + ty); } } } } // 匈牙利 memset(match, -1, sizeof match); int res = 0; for (int i = 1; i <= n * m; i++) { memset(st, 0, sizeof st); if (dfs(i)) res++; } // 无向图,重复计算,然后除以2,就是最大匹配数 printf("%d\n", cnt - res / 2); } return 0; }