题目:一个矩形可以划分成M*N个小正方形,其中有一些小正方形不能使用。一个多米诺骨牌占用两个相邻的小正方形。试问整个区域内最多可以不重叠地放多少个多米诺骨牌且不占用任何一个被标记为无法使用的小正方形。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,m,k,size=0,g;
int can[60][60],code[60][60],num[60][60],ffff[5510];
int v[5510],first[5510],next[5010];
int vis[5510];
void init()
{
}
void readdata()
{
memset(next,-1,sizeof(next));
memset(first,-1,sizeof(first));
memset(can,1,sizeof(can));
memset(code,1,sizeof(code));
memset(ffff,-1,sizeof(ffff));
scanf("%d%d%d",&m,&n,&k);
for(int i=1;i<=k;i++)
{
int x,y;
scanf("%d%d",&x,&y);
can[x][y]=0;
}
}
void insert(int x,int y)
{
size++;
v[size]=y;
next[size]=first[x];
first[x]=size;
}
bool in(int x,int y)
{
if(x>0&&x<=m&&y>0&&y<=n) return true;
else return false;
}
void makemap()
{
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(code[i][j])
{
code[i-1][j]=0;
code[i+1][j]=0;
code[i][j-1]=0;
code[i][j+1]=0;
}
}
}
int x=0,y=0;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(can[i][j])
{
if(code[i][j])
{
x++;
num[i][j]=x;
}
}
}
}
g=x;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(can[i][j])
{
if(!code[i][j])
{
y++;
num[i][j]=y;
}
}
}
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(can[i][j])
{
if(code[i][j])
{
if(can[i-1][j]&&in(i-1,j))
{
insert(num[i][j],num[i-1][j]);
}
if(can[i+1][j]&&in(i+1,j))
{
insert(num[i][j],num[i+1][j]);
}
if(can[i][j-1]&&in(i,j-1))
{
insert(num[i][j],num[i][j-1]);
}
if(can[i][j+1]&&in(i,j+1))
{
insert(num[i][j],num[i][j+1]);
}
}
}
}
}
}
int clockvis;
bool find(int k)
{
for(int e=first[k];e!=-1;e=next[e])
{
int y=v[e];
if(vis[y]==clockvis) continue;
vis[y]=clockvis;
if(ffff[y]==-1 || find(ffff[y]))
{
ffff[y]=k;
return true;
}
}
return false;
}
void work()
{
makemap();
int ans=0;
for(int i=1;i<=g;i++)
{
clockvis=i;
if(find(i)) ans++;
}
printf("%d\n",ans);
}
int main()
{
init();
readdata();
work();
return 0;
}