UVA11261 Bishops

给出一个n*n的棋盘和m个象。每一个象可以覆盖它所在的对角线,问没有被覆盖的点有多少个

对于一头大象它能够覆盖它所在的从对角线和主对角线,可是些对角线可能相互交叉,因此不能直接求对角线上面的点的个数。

n*n的暴力方法非常好想出来,可是肯定超时。

我们能够把主对角线和从对角线保存下来,预处理好没有被覆盖的点,dp[i]表示第i条从对角线上面没有被覆盖的点,一共同拥有2*n-1条从对角线。

对于从对角线的上半部分,dp[i]初始化为dp[i-2]由于他们的奇偶性同样,则除去第i条从对角线的两个端点以外。假设第i-2条从对角线上的某个点被一条主对角线覆盖,那么它右下角相应的从对角线上的点也被覆盖。

时间复杂度为O(N)。


#include<cstdio>
#include<cstring>
#define MAXN 80005
using namespace std;
bool cover_positive[MAXN];//主对角线是否被覆盖
bool cover_negative[MAXN];//从对角线是否被覆盖
int dp[MAXN];//保存第i条从对角线有多少个点没有被覆盖
int n,m;
int main()
{
	int T;
	scanf("%d",&T);
	int cnt = 0;
	while(T--)
	{
		memset(cover_positive,0,sizeof cover_positive);
		memset(cover_negative,0,sizeof cover_negative);
		memset(dp,0,sizeof dp);
		scanf("%d%d",&n,&m);
		int x,y;
		for(int i = 1; i <= m; i++)
		{
			scanf("%d%d",&x,&y);
			cover_positive[n+x-y] = 1;
			cover_negative[x+y-1] = 1;
		}
		
		if(!cover_positive[n]) dp[2*n-1] = dp[1] = 1;//第n条主对角线没有被覆盖。因此第1和第2n-1条对角线上面有一个没有被覆盖的点
		for(int i = 2; i <= n; i++)
		{
			dp[i] = dp[i-2];//dp[i]由dp[i-2]转移过来,第i条对角线比第i-2条对角线多左下和右上2个点,
			//假设第i-2条对角线的其它点被覆盖,那么第i条对角线上的点也会被覆盖
			int num = n - i + 1;
			if(!cover_positive[num]) ++dp[i];
			if(!cover_positive[2*n-num]) ++dp[i];
		}
		for(int i = 2*n-2; i >= n+1; i--)
		{
			dp[i] = dp[i+2];//另外一半对角线与之前的一半相反
			int num = i - n + 1;
			if(!cover_positive[num]) ++dp[i];
			if(!cover_positive[2*n-num]) ++dp[i];
		}
		
		int ans = 0;
		for(int i = 1; i < 2*n; i++)
			if(!cover_negative[i])
				ans += dp[i];
		printf("Case #%d: %d\n",++cnt,ans);
	}
}


posted on 2017-05-03 12:40  ljbguanli  阅读(101)  评论(0编辑  收藏  举报