You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

78 lines
2.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
const int N = 510, M = N * N * 2;
int dx[] = {0, 0, -1, 1};
int dy[] = {-1, 1, 0, 0};
// 链式前向星
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 st[N], match[N];
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;
}
char g[50][50];
int id[50][50];
int main() {
#ifndef ONLINE_JUDGE
freopen("LightOJ1152.in", "r", stdin);
#endif
int T, n, m, cas = 0;
scanf("%d", &T);
while (T--) {
// 初始化链式前向星
memset(h, -1, sizeof h);
idx = 0;
scanf("%d%d", &n, &m);
// 按char[]数组读入原始地图
for (int i = 1; i <= n; i++) scanf(" %s", g[i] + 1);
// 给每个金子编号,相当于离散化
memset(id, 0, sizeof id);
int cnt = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (g[i][j] == '*') id[i][j] = ++cnt;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (id[i][j]) {
for (int k = 0; k < 4; k++) {
int tx = i + dx[k], ty = j + dy[k];
if (!id[tx][ty]) continue;
if (tx < 1 || tx > n || ty < 1 || ty > m) continue;
add(id[i][j], id[tx][ty]); // 对每个金子,和它四个方向上的金子连边,没有就不连
}
}
int res = 0;
memset(match, -1, sizeof match);
for (int i = 1; i <= cnt; i++) {
memset(st, 0, sizeof st);
if (dfs(i)) res++;
}
/*
*由于对每个金子拆点求出的最大匹配是双倍的除以2才是真正的最大匹配不除以2则是匹配的点
*那么节点数 - 匹配的点 = 落单的个数。明显落单的金子每个需要一个骨牌,匹配的点两个需要一个骨牌
*于是,答案= 节点 - 匹配点 + 匹配点 / 2
*/
printf("Case %d: %d\n", ++cas, cnt - res / 2);
}
return 0;
}