每个*作为二分图点集中的一个点,每个天线可以覆盖两个*,天线就看到成是连接不同集合的点的边,因为不知道这些*属于那个集合,所以就建双向的,最后结果除2。
问最少多少天线覆盖所有的点,就是问二分图的最小边覆盖,最小边覆盖=点数-最大匹配数。
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#define maxn 800
using namespace std;
char _tmp[maxn][maxn];
bool _map[maxn][maxn];
int num[maxn][maxn];
int pre[maxn];
bool vis[maxn];
int mr[]={0,1};
int mc[]={1,0};
bool find_path(int pos,int n)
{
for(int i=1;i<=n;++i)
{
if(_map[pos][i] && !vis[i])
{
vis[i]=true;
if(pre[i]==0 || find_path(pre[i],n))
{
pre[i]=pos;
return true;
}
}
}
return false;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int r,c;
scanf("%d%d",&r,&c);
memset(num,0,sizeof(num));
int t=1;
for(int i=0;i<r;++i)
{
scanf("%s",_tmp[i]);
for(int j=0;j<c;++j)
{
if(_tmp[i][j]=='*')
num[i][j]=t++;
}
}
memset(_map,false,sizeof(_map));
for(int i=0;i<r;++i)
{
for(int j=0;j<c;++j)
{
if(num[i][j]!=0)
{
for(int k=0;k<2;++k)
{
int nowi=i+mr[k];
int nowj=j+mc[k];
if(nowi>=0 && nowj>=0 && nowi<r && nowj<c && num[nowi][nowj]!=0)
{
int x=num[i][j],y=num[nowi][nowj];
_map[x][y]=true;
_map[y][x]=true;
}
}
}
}
}
int n=t-1;
int ans=0;
memset(pre,false,sizeof(pre));
for(int i=1;i<=n;++i)
{
memset(vis,false,sizeof(vis));
if(find_path(i,n))
{
ans++;
}
}
printf("%d\n",n-ans/2);
}
}