http://acm.pku.edu.cn/JudgeOnline/problem?id=3020
题意:给出N*M大小的棋盘,棋盘以'*'与'o'组成,现在要求用1*2大小的矩形覆盖这些'*'的点,问最少要用多少个.
思想:此题与Chessboard很相近,就是把棋盘进行编号,如果某点是'*',则与其上下左右为'*'的点建立边,不过此题
建立的是双向边,找到的最大匹配数要div2,利用个数=顶点数-最大匹配div2,就可以啦!
源码:
#include<iostream>
using namespace std;
#define MaxInt 402
int xM[MaxInt],yM[MaxInt];
bool chk[MaxInt];
bool Map[MaxInt][MaxInt];
char base[42][12];
int x,y;
int n,m,k;
bool dfs(int u)
{
int v;
for(v=1;v<=y;v++)
{
if(Map[u][v]&&!chk[v])
{
chk[v]=true;
if(yM[v]==-1||dfs(yM[v]))
{
yM[v]=u;
xM[u]=v;
return true;
}
}
}
return false ;
}
int main()
{
int i,j;
int num;
scanf("%d",&k);
while(k--)
{
scanf("%d%d",&n,&m);
num=0;
for(i=1;i<=n;i++)
scanf("%s",base[i]+1);
memset(Map,false,sizeof(Map));
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(base[i][j]=='*')
{
++num;
x=(i-1)*m+j;
if(i>1&&base[i-1][j]=='*')
{
Map[x][x-m]=true;
Map[x-m][x]=true;
}
if(i<n&&base[i+1][j]=='*')
{
Map[x][x+m]=true;
Map[x+m][x]=true;
}
if(j>1&&base[i][j-1]=='*')
{
Map[x][x-1]=true;
Map[x-1][x]=true;
}
if(j<m&&base[i][j+1]=='*')
{
Map[x][x+1]=true;
Map[x+1][x]=true;
}
}
}
}
memset(xM,0xff,sizeof(xM));
memset(yM,0xff,sizeof(yM));
j=0;
x=y=n*m;
for(i=1;i<=x;i++)
{
if(xM[i]==-1)
{
memset(chk,false,sizeof(chk));
if(dfs(i))
j++;
}
}
printf("%d/n",num-j/2);
}
return 0;
}