原题链接
考察:二分图匹配
思路:
实际考察最小覆盖点.将文物与它的关键点建边.除此之外我们需要将点分为两个集合.可以发现每个点与它的关键点奇偶性不同.由此将点分为\(x+y\)为奇和偶两个集合.
注意建边,需要\((x,y)\)为关键点与文物建边,\((x,y)\)与它的关键点建边.
Code
#include <iostream>
#include <cstring>
using namespace std;
typedef pair<int,int> PII;
const int N = 55;
int m,n,mp[N][N];
PII match[N][N];
bool st[N][N];
int xx[13] = {-1,-2,-2,-1,1,2,2,1,-1,0,1,0};
int yy[13] = {-2,-1,1,2,2,1,-1,-2,0,1,0,-1};
int dir[13] = {4,6,8,10,4,6,8,10,18,20,18,20};
bool dfs(int x,int y)
{
for(int i=0;i<12;i++)
{
int dx = x+xx[i],dy = y+yy[i];
if(dx>=1&&dx<=m&&dy>=1&&dy<=n&&mp[dx][dy]!=-1&&!st[dx][dy])
{
if(!(mp[x][y]>>i&1)&&!(mp[dx][dy]>>(dir[i]-i)&1)) continue;
st[dx][dy] = 1;
if(!match[dx][dy].first||dfs(match[dx][dy].first,match[dx][dy].second))
{
match[dx][dy] = {x,y};
return 1;
}
}
}
return 0;
}
int main()
{
int kcase = 0;
while(scanf("%d%d",&m,&n)!=EOF&&(n+m))
{
memset(match,0,sizeof match);
for(int x=1;x<=m;x++)
for(int y=1;y<=n;y++)
scanf("%d",&mp[x][y]);
int res = 0;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if((i+j&1))
{
if(mp[i][j]==-1) continue;
memset(st,0,sizeof st);
if(dfs(i,j)) ++res;
}
printf("%d. %d\n",++kcase,res);
}
return 0;
}