题目大意:给定一个坐标图,图中每在一个点上覆盖就可在覆盖它上下左右4个点中任一个,问最少放几个。
思路:把每一个点都和与之相邻的4个点连边,就构成了一个二分图。利用匈牙利算法,最后输出的时候需要注意的是这里的点是所有可以放的点的两倍,而匹配数也是正常匹配数的二倍(A到B连了,B到A也连了),所以输出的时候应该先将匹配数除以2。
#include <iostream>
using namespace std;
#include <stdio.h>
#include <memory.h>
#include <string.h>
const int SIZE = 520;
int data[SIZE][SIZE];
int matched[SIZE];
int used[SIZE];
char str[50][20];
int n;
int dfs(int m) {
int i;
for ( i=1;i<=n;i++ ) {
if ( used[i]==0&&data[m][i]==1 ) {
used[i]=1;
if ( matched[i]==-1||dfs(matched[i]) ) {
matched[i]=m;
return 1;
}
}
}
return 0;
}
int Hungary() {
int i,ctr;
ctr=0;
for ( i=1;i<=n;i++ ) {
memset(used,0,sizeof(used));
if ( dfs(i) )
ctr++;
}
return ctr;
}
//初始化数据
int initialization(int h,int w) {
int ctr,i,j;
int x,y;
int s,d;
ctr=0;
for ( i=1;i<=h;i++ ) {
for ( j=1;j<=w;j++ ) {
if ( str[i][j]=='*' ) {
ctr++;
x=i;
y=j;
s=(x-1)*w+y;
if ( y+1<=w&&str[x][y+1]=='*' ) {
d=(x-1)*w+y+1;
data[s][d]=1;
// printf("%d %d\n",s,d);
}
if ( x+1<=h&&str[x+1][y]=='*' ) {
d=(x)*w+y;
data[s][d]=1;
// printf("%d %d\n",s,d);
}
if ( y-1>=1&&str[x][y-1]=='*' ) {
d=(x-1)*w+y-1;
data[s][d]=1;
// printf("%d %d\n",s,d);
}
if ( x-1>=1&&str[x-1][y]=='*' ) {
d=(x-2)*w+y;
data[s][d]=1;
// printf("%d %d\n",s,d);
}
}
}
}
// printf("%d\n",ctr);
return ctr;
}
int main()
{
int result,i,t,h,w,j,temp;
scanf("%d",&t);
while (t--) {
scanf("%d%d",&h,&w);
getchar();
memset(data,0,sizeof(data));
memset(matched,-1,sizeof(matched));
for ( i=1;i<=h;i++ ) {
for ( j=1;j<=w;j++ ) {
scanf("%c",&str[i][j]);
}
getchar();
}
temp=initialization(h,w);
n=h*w;
result=Hungary();
printf("%d\n",temp-result/2);
}
return 0;
}