National Treasures HDU - 3360

原题链接
考察:二分图匹配
思路:
??实际考察最小覆盖点.将文物与它的关键点建边.除此之外我们需要将点分为两个集合.可以发现每个点与它的关键点奇偶性不同.由此将点分为\(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;
}

National Treasures HDU - 3360

上一篇:Educational Codeforces Round 111 (Rated for Div. 2) D. Excellent Arrays


下一篇:ARM寄存器R15存放偏移量计算的问题