建模:
将所有的'*'作为X集合,边表示两个点相邻,如此建立的二部图,求出的最大匹配,需要进行处理:
我们发现对于已匹配点,都覆盖了两次,还要加上没有匹配到的点。
// rank:47 132K 0MS 2010-06-06 15:55:48
// Type:二分匹配
#include < stdio.h >
#include < string .h >
#define HL 44
#define WL 11
int adj[HL * WL][ 5 ];
int mth[HL * WL];
bool used[HL * WL];
char ms[HL][WL];
int flg[HL][WL];
int dir[ 4 ][ 2 ] = {{ 0 , - 1 }, { 0 , 1 }, { 1 , 0 }, { - 1 , 0 }};
int n;
bool path( int u)
{
for ( int v = 1 ; v <= adj[u][ 0 ]; v ++ ) {
int t = adj[u][v];
if ( ! used[t]) {
used[t] = 1 ;
if ( ! mth[t] || path(mth[t])) {
mth[t] = u;
return 1 ;
}
}
}
return 0 ;
}
int main()
{
int T, h, w;
int i, j, k;
int match;
scanf( " %d " , & T);
while (T -- ) {
scanf( " %d%d " , & h, & w);
for (i = 0 ; i < h; i ++ ) {
scanf( " %s " , ms[i]);
}
n = 0 ;
for (i = 0 ; i < h; i ++ ) {
for (j = 0 ; j < w; j ++ ) {
if (ms[i][j] == ' * ' ) {
flg[i][j] = ++ n;
}
}
}
memset(adj, 0 , sizeof (adj));
for (i = 0 ; i < h; i ++ ) {
for (j = 0 ; j < w; j ++ ) {
if (ms[i][j] == ' * ' ) {
for (k = 0 ; k < 4 ; k ++ ) {
int x = i + dir[k][ 0 ];
int y = j + dir[k][ 1 ];
if (x >= 0 && x < h
&& y >= 0 && y < w
&& ms[x][y] == ' * ' ) {
int f1 = flg[i][j];
int f2 = flg[x][y];
adj[f1][ ++ adj[f1][ 0 ]] = f2;
}
}
}
}
}
match = 0 ;
memset(mth, 0 , sizeof (mth));
for (i = 1 ; i <= n; i ++ ) {
memset(used, 0 , sizeof (used));
if (path(i)) {
match ++ ;
}
}
printf( " %d\n " , n - match / 2 );
}
return 0 ;
}