题目链接:http://soj.sysu.edu.cn/1172
题目大意:在一个棋盘上,放着皇后、骑士和兵三种棋子。其中皇后有八个方向可以占位(即在该方向上的位置不能再放棋子),但是如果其遇到任何的另一个棋子,其在该方向上的在两个棋子外的部分将不会被占位,比如:一个4*4的棋盘,有一个骑士在(1,2),有一个皇后在(1,4)那么(1,1)将不会被皇后占位;对于骑士,其占位的方向是“日”字型的,即2*3的矩阵的对角;而兵只是简单的在自己的位置上占位而不提供其他功能。
解题思路:直接按题目要求模拟。
这里需要注意的是皇后受阻挡并不会发生在由其他棋子所产生的占位的情况下。比如下图中,在(1,2)和(3,4)处有一个皇后,那么黑色1 的方格就是(1,2)皇后产生的占位,此时对于(3,4)的皇后,其所产生的占位是红色 1 和蓝色 1 的方格。这里需要注意的就是蓝色 1 这个位置,(3,4)皇后并不会因为有(3,2)的占位而受阻,其仍然会对(3,1)发生作用。
#include <stdio.h>
// 用于记录棋盘上该位置是否还能用,0 表示能用,1和2表示不能用
// 其中,1表示放上棋子后由棋子所产生的占位,2表示棋子本身的占位
int occupied[1010][1010];
struct Point // 棋子坐标
{
int x; // 横坐标
int y; // 纵坐标
};
int main()
{
int n, m, cnt = 1, queen_num, knight_num, pawn_num, count, x, y;
Point queens[110], knight[110], pawn[110];
while (1)
{
scanf("%d %d", &m, &n);
if (n == 0 && m == 0)
break;
// 初始化棋盘所有位置为未被占用
for (int i = 0; i < m + 2; i++)
for (int j = 0; j < n + 2; j++)
occupied[i][j] = 0;
// 读皇后的数据并初始化
scanf("%d", &queen_num);
for (int i = 0; i < queen_num; i++)
{
scanf("%d %d", &queens[i].x, &queens[i].y);
occupied[queens[i].x][queens[i].y] = 2;
}
// 读骑士的数据并初始化
scanf("%d", &knight_num);
for (int i = 0; i < knight_num; i++)
{
scanf("%d %d", &knight[i].x, &knight[i].y);
occupied[knight[i].x][knight[i].y] = 2;
}
// 读兵的数据并初始化
scanf("%d", &pawn_num);
for (int i = 0; i < pawn_num; i++)
{
scanf("%d %d", &pawn[i].x, &pawn[i].y);
occupied[pawn[i].x][pawn[i].y] = 2;
}
// 更新皇后棋子所产生的占位
for (int k = 0; k < queen_num; k++)
{
x = queens[k].x;
y = queens[k].y;
// 竖直向上方向
for (int i = x - 1; i > 0; i--)
{
if (occupied[i][y] == 2)
break;
occupied[i][y] = 1;
}
// 竖直向下方向
for (int i = x + 1; i <= m; i++)
{
if (occupied[i][y] == 2)
break;
occupied[i][y] = 1;
}
// 水平向左方向
for (int i = y - 1; i > 0; i--)
{
if (occupied[x][i] == 2)
break;
occupied[x][i] = 1;
}
// 水平向右方向
for (int i = y + 1; i <= n; i++)
{
if (occupied[x][i] == 2)
break;
occupied[x][i] = 1;
}
// 左下方向
for (int i = x + 1, j = y - 1; i <= m && j > 0; i++, j--)
{
if (occupied[i][j] == 2)
break;
occupied[i][j] = 1;
}
// 左上方向
for (int i = x - 1, j = y - 1; i >0 && j > 0; i--, j--)
{
if (occupied[i][j] == 2)
break;
occupied[i][j] = 1;
}
// 右上方向
for (int i = x - 1, j = y + 1; i > 0 && j <= n; i--, j++)
{
if (occupied[i][j] == 2)
break;
occupied[i][j] = 1;
}
// 右下方向
for (int i = x + 1, j = y + 1; i <= m && j <= n; i++, j++)
{
if (occupied[i][j] == 2)
break;
occupied[i][j] = 1;
}
}
// 更新骑士棋子所产生的占位
for (int i = 0; i < knight_num; i++)
{
x = knight[i].x;
y = knight[i].y;
if (x + 1 <= m && y + 2 <= n)
occupied[x + 1][y + 2] = 1;
if (x - 1 > 0 && y + 2 <= n)
occupied[x - 1][y + 2] = 1;
if (x + 2 <= m && y + 1 <= n)
occupied[x + 2][y + 1] = 1;
if (x - 2 > 0 && y + 1 <= n)
occupied[x - 2][y + 1] = 1;
if (x + 1 <= m && y - 2 > 0)
occupied[x + 1][y - 2] = 1;
if (x - 1 > 0 && y - 2 > 0)
occupied[x - 1][y - 2] = 1;
if (x - 2 > 0 && y - 1 > 0)
occupied[x - 2][y - 1] = 1;
if (x + 2 <= m && y - 1 > 0)
occupied[x + 2][y - 1] = 1;
}
// 计算还有多少个位置没被占用
count = 0;
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
if (occupied[i][j] == 0)
count++;
printf("Board %d has %d safe squares.\n", cnt++, count);
}
return 0;
}