/*
http://poj.org/problem?id=3020
题目大意:N个城市,一个基站可以覆盖相邻的两个城市,求最少需要几个基站
建模:建立无向的N*N二分图(不能建成有向的图,打表可以看出来),求最大匹配P。
这里的匹配,可以理解为相邻两个基站的匹配。那么N=P*2+单独的城市
而我们要求的最少基站数=P+单独的城市
所以N-P,就是最少需要的基站数
由于是无向图,所以最大匹配多算了一倍,即1和2配对会成为1-2,2-1两条配对,只要除以2就可以了
网上有很多把这题转成最小路径覆盖的解法,列举一个
路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联
1.一个单独的顶点是一条路径
2.如果存在一路径p1,p2,......pk,其中p1 为起点,pk为终点,那么在覆盖图中,顶点p1,p2,......pk不再与其它的顶点之间存在有向边.
最小路径覆盖就是找出最小的路径条数,使之成为P的一个路径覆盖.
定理:最小路径覆盖=最大匹配
*/
#include
<iostream>
#include
<cstdio>
#include
<cstring>
#include
<string>
using
namespace
std;
const
int
N=
500
;
int
n,
m,
num;
char
str[
20
];
int
mate_x[
N];
int
mate_y[
N];
bool
path[
N][
N];
bool
visited[
N];
int
dx[
4
]=
{
0
,
0
,-
1
,
1
}
;
int
dy[
4
]=
{
-
1
,
1
,
0
,
0
}
;
struct
P
{
int
x,
y;
}
p[
N];
int
find
(
int
u)
{
for
(
int
v=
1
;
v<=
m;
v++)
{
if
(
path[
u][
v]&&!
visited[
v])
{
visited[
v]=
true
;
if
(
mate_y[
v]==-
1
||
find
(
mate_y[
v]))
{
mate_x[
u]=
v;
mate_y[
v]=
u;
return
1
;
}
}
}
return
0
;
}
bool
isNeighbour
(
int
i,
int
j)
{
for
(
int
k=
0
;
k<
4
;
k++)
if
(
p[
i].
x+
dx[
k]==
p[
j].
x&&
p[
i].
y+
dy[
k]==
p[
j].
y)
return
true
;
return
false
;
}
int
main
()
{
int
T,
h,
w;
cin>>
T;
while
(
T--)
{
scanf
(
"%d%d"
,&
h,&
w);
num=
1
;
for
(
int
i=
0
;
i<
h;
i++)
{
scanf
(
"%s"
,
str);
for
(
int
j=
0
;
j<
w;
j++)
if
(
str[
j]==
'*'
)
{
p[
num].
x=
i;
p[
num++].
y=
j;
}
}
for
(
int
i=
1
;
i<
num;
i++)
for
(
int
j=
1
;
j<
num;
j++)
path[
i][
j]=
isNeighbour
(
i,
j);
memset
(
mate_x,-
1
,
sizeof
(
mate_x));
memset
(
mate_y,-
1
,
sizeof
(
mate_y));
n=
num;
m=
num;
int
ans=
0
;
for
(
int
u=
1
;
u<
num;
u++)
{
memset
(
visited,
false
,
sizeof
(
visited));
if
(
mate_x[
u]==-
1
&&
find
(
u))
ans++;
}
cout<<
num-1
-
ans/
2
<<
endl;
}
}