说来惭愧,看了别人的题解之后知道解题步骤,却不知道原理,也就是说,不知其所以然,哎…
步骤就是:将所有相邻的点建立无向图,之后求最小边覆盖,即为答案。
/*************************************************************************
> File Name: main.cpp
> Author:Eagles
> Mail:None
> Created Time: 2018年09月15日 星期六 21时42分11秒
> Description:POJ3020
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define N 1000
struct node
{
int to;
int nex;
}E[N*N];
int head[N];
int map[N][N];
int vis[N];
int pre[N];
int n,cnt;
int h,w;
bool city[N][N];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
void addEdge(int a, int b)
{
E[cnt].to=b;
E[cnt].nex=head[a];
head[a]=cnt++;
}
bool check(int x, int y)
{
return (0<=x&&x<h&&0<=y&&y<w&&map[x][y]);
}
void init()
{
memset(head,-1,sizeof(head));
memset(pre,-1,sizeof(pre));
memset(city,false,sizeof(city));
memset(map,0,sizeof(map));
cnt=n=0;
for (int i=0; i<h; i++)
{
for (int j=0; j<w; j++)
{
char ch;
scanf("%c",&ch);
if (ch=='*')
map[i][j]=++n;
}
getchar();
}
for (int i=0; i<h; i++)
{
for (int j=0; j<w; j++)
{
if (map[i][j])
{
for (int k=0; k<4; k++)
{
int x=i+dir[k][0];
int y=j+dir[k][1];
if (check(x,y))
{
city[map[i][j]][map[x][y]]=true;
}
}
}
}
}
for (int i=0; i<=n; i++)
{ for (int j=0; j<=n; j++)
{
if (city[i][j])
addEdge(i,j);
}
}
}
int dfs(int x)
{
for (int i=head[x]; i!=-1; i=E[i].nex)
{
if (!vis[E[i].to])
{
vis[E[i].to]=true;
if (pre[E[i].to]==-1||dfs(pre[E[i].to]))
{
pre[E[i].to]=x;
return 1;
}
}
}
return 0;
}
int hungary()
{
int sum=0;
for (int i=1; i<=n; i++)
{
memset(vis,false,sizeof(vis));
if (dfs(i))
sum++;
}
return n-sum/2;
}
int main()
{
int t;
while (~scanf("%d",&t))
{
while (t--)
{
scanf("%d%d",&h,&w);
getchar();
init();
printf("%d\n",hungary());
}
}
return 0;
}