题目链接:http://poj.org/problem?id=3020
题意:相邻两个点可以圈起来,问图中所有的'*'点都被圈起来需要的最小的圈的个数。
分析:1.建二分图;
图中的点可以二分,
2.做二分匹配;ans='*'点的个数-最大匹配;
//poj3020
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn=1000;
int hash[maxn];
int h,w,tot;
int f[maxn];//记录当前的映射关系;
bool vis[maxn];
int a[4][2]={1,0,0,-1,-1,0,0,1};
struct edge
{
int v,next;
}e[maxn*10];
void add(int u,int v)
{
tot++;
e[tot].v=v;
e[tot].next=hash[u];
hash[u]=tot;
}
int dfs(int p)//点p找到新的匹配,返回1,否则,返回0;
{
vis[p]=1;
for (int i=hash[p];i!=-1;i=e[i].next)
{
int v=e[i].v;
int t=f[v];
f[v]=p;
if (!vis[t]&&(t==0||dfs(t))) return 1;
f[v]=t;
}
return 0;
}
int main()
{
//freopen("in.txt","r",stdin);
int T;
cin>>T;
while (T--)
{
cin>>h>>w;
tot=0;
memset(hash,-1,sizeof(hash));
int s[500][500];
memset(s,0,sizeof(s));
int num=0;
char c;
int ans=0;
while (num<h*w)
{
scanf("%c",&c);
while (c!='*'&&c!='o') scanf("%c",&c);
if (c=='*')
{
s[num/w][num%w]=1;
ans++;
}
num++;
}
for (int i=0;i<h;i++)
for (int j=i%2;j<w;j+=2)
if (s[i][j]==1)
{
for (int k=0;k<4;k++)
{
int x=i+a[k][0],y=j+a[k][1];
if ((x>=0)&&(x<h)&&(y>=0)&&(y<w)&&(s[x][y]==1))
add(i*w+j+1,x*w+y+1);
}
}
memset(f,0,sizeof(f));
for (int i=1;i<=h*w;i++)
{
memset(vis,0,sizeof(vis));
ans-=dfs(i);
}
cout<<ans<<endl;
}
}