题意:一个地图由o
和*
组成,一个信号塔可以覆盖两个连续的*
。问至少需要多少个信号塔才能覆盖所有的*
。
思路:先将所有的’*’hash,然后建立二分图,用匈牙利算法算出最大匹配数。最小路径覆盖数 = 顶点数 - 最大匹配数
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
bool path[410][410], used[410];
int match[410];
int num;
bool Dfs(int x)
{
for (int i = 1; i <= num; i++)
{
if (!used[i] && path[x][i])
{
used[i] = true;
if (!match[i] || Dfs(match[i]))
{
match[i] = x;
return true;
}
}
}
return false;
}
int Matching()
{
int ans = 0;
memset(match, 0, sizeof(match));
for (int i = 1; i <= num; i++)
{
memset(used, false, sizeof(used));
if (Dfs(i))
{
ans++;
}
}
return ans;
}
int main(void)
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d", &T);
while (T--)
{
int n,m;
int a[50][20];
char mp[50][20];
memset(a,0,sizeof(a));
memset(path,false,sizeof(path));
memset(mp, 0, sizeof(mp));
num = 1;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++)
scanf(" %s", mp[i]);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (mp[i][j]=='*')
a[i][j] = num++;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (a[i][j])
{
if (i-1>=0 && a[i-1][j])
path[a[i][j]][a[i-1][j]] = true;
if (i+1<n && a[i+1][j])
path[a[i][j]][a[i+1][j]] = true;
if (j-1>=0 && a[i][j-1])
path[a[i][j]][a[i][j-1]] = true;
if (j+1<m && a[i][j+1])
path[a[i][j]][a[i][j+1]] = true;
}
}
}
num--;
int ans = Matching();
printf("%d\n", num-ans/2);
}
return 0;
}