有机会要自己写一下,主要的还是怎么构造二分图
思路:匈牙利算法,每两个合法(相邻)的星号连一条边,很明显这是一个最小覆盖的问题,但是在构图过程中,匹配是双向的,即
#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
int ans, h, w, W[45][15], link[405];
bool cm[405][405],vis[405];
int dir[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
bool dfs(int r,int t)
{
int i, j;
for (i = 1; i <= t; i++)
{
if (!vis[i] && cm[r][i])
{
vis[i] = 1;
if (link[i]==0 || dfs(link[i],t))
{
link[i] = r;
return true;
}
}
}
return false;
}
void search(int t)
{
int i;
ans = 0;
for (i = 1; i <= t; i++)
{
memset(vis, 0, sizeof(vis));
if (dfs(i, t))
ans++;
}
}
int main(void)
{
//freopen("1.txt", "r", stdin);
int i, j, t, k, cases, a, b;
char tmp[50];
scanf("%d", &cases);
while (cases > 0)
{
t = 1;
scanf("%d%d", &h, &w);
memset(W, 0, sizeof(W));
memset(cm, 0, sizeof(cm));
memset(link, 0, sizeof(link));
for (i = 0; i < h; i++)
{
scanf("%s", tmp);
for (j = 0; j < w; j++)
{
if (tmp[j] == '*')
W[i][j] = t++;
}
}
for (i = 0; i < h; i++)
{
for (j = 0; j < w; j++)
{
for (k = 0; k < 4; k++)
{
a = i + dir[k][0];
b = j + dir[k][1];
if (a >= 0 && a < h&&b >= 0 && b < w)
{
cm[W[i][j]][W[a][b]] = 1;
}
}
}
}
search(t);
printf("%d\n", t - 1 - ans / 2);
cases--;
}
}