题目描述:
现在,我们用大炮来打蚊子:蚊子分布在一个M×N格的二维平面上,每只蚊子占据一格。向该平面的任意位置发射炮弹,炮弹的杀伤范围如下示意:
O
OXO
O
其中,X为炮弹落点中心,O
为紧靠中心的四个有杀伤力的格子范围。若蚊子被炮弹命中(位于X
格),一击毙命,若仅被杀伤(位于O
格),则损失一半的生命力。也就是说,一次命中或者两次杀伤均可消灭蚊子。现在给出蚊子的分布情况以及连续k
发炮弹的落点,给出每炮消灭的蚊子数。
输入格式:
第一行为两个不超过20的正整数M
和N
,中间空一格,表示二维平面有M
行、N
列。
接下来M
行,每行有N
个0
或者#
字符,其中#
表示所在格子有蚊子。
接下来一行,包含一个不超过400的正整数k
,表示发射炮弹的数量。
最后k
行,每行包括一发炮弹的整数坐标x
和y
(0≤x
<M
,0≤y
<N
),之间用一个空格间隔。
输出格式:
对应输入的k
发炮弹,输出共有k
行,第i
行即第i
发炮弹消灭的蚊子数。
输入样例:
5 6
00#00#
000###
00#000
000000
00#000
2
1 2
1 4
输出样例:
0
2
代码实现:
#include <stdio.h>
// 定义蚊子状态
#define MOSQUITO_ALIVE '#'
#define MOSQUITO_DEAD '0'
int main()
{
// 读取平面大小
int m, n;
scanf("%d %d", &m, &n);
// 读取平面上的蚊子分布情况
char grid[20][20];
int i = 0, j = 0, p = 0;
for (i = 0; i < m; i ++) {
scanf("%s", grid[i]);
}
//初始化每个蚊子的生命值
int healthPoint[20][20] = {0};
for (i = 0;i < m; i ++) {
for (j = 0; j < n; j ++) {
if (grid[i][j] == MOSQUITO_ALIVE) {
healthPoint[i][j] = 2;
}
}
}
//定义一个数组用于存放结果
int result[20];
int q = 0;
// 读取炮弹数量
int k;
scanf("%d", &k);
// 处理每一发炮弹
int x, y;
for(i = 0; i < k; i ++) {
scanf("%d %d", &x, &y);
// 计算消灭的蚊子数
int countMosquitoes = 0;
//一击毙命
if (healthPoint[x][y] != 0) {
healthPoint[x][y] = 0;
grid[x][y] = MOSQUITO_DEAD;
countMosquitoes++;
}
//击伤(检查四个方向)
if (x - 1 >= 0 && healthPoint[x - 1][y] != 0) {
healthPoint[x - 1][y] -= 1;
if(healthPoint[x - 1][y] == 0) {
grid[x - 1][y] = MOSQUITO_DEAD;
countMosquitoes++;
}
}
if (x + 1 < m && healthPoint[x + 1][y] != 0) {
healthPoint[x + 1][y] -= 1;
if(healthPoint[x + 1][y] == 0) {
grid[x + 1][y] = MOSQUITO_DEAD;
countMosquitoes++;
}
}
if (y - 1 >= 0 && healthPoint[x][y - 1] != 0) {
healthPoint[x][y - 1] -= 1;
if(healthPoint[x][y - 1] == 0) {
grid[x][y - 1] = MOSQUITO_DEAD;
countMosquitoes++;
}
}
if (y + 1 < n && healthPoint[x][y + 1] != 0) {
healthPoint[x][y + 1] -= 1;
if(healthPoint[x][y + 1] == 0) {
grid[x][y + 1] = MOSQUITO_DEAD;
countMosquitoes++;
}
}
result[q++] = countMosquitoes;
}
for(i = 0; i < k; i ++) {
if (i < k - 1)
printf("%d\n", result[i]);
else
printf("%d", result[i]);
}
return 0;
}
代码详解:
总体思路:
本题主要是要解决处理每一发炮弹落点的问题,无非是三种情况:(1)炮弹正好落在蚊子上,蚊子被一击毙命;(2)以炮弹落点为中心的上下左右四个方向有蚊子,则蚊子被杀伤;(3)炮弹既没有击毙任何蚊子也没有杀伤任何蚊子。
可知,蚊子有两种死法:被一击毙命或者被两次杀伤而死。
则可以考虑创建两个数组,一个字符型数组用于读入输入的二维平面上蚊子分布状态,一个整形数组用于定义二维平面上每个蚊子当前的生命值
代码部分讲解:
// 定义蚊子状态
#define MOSQUITO_ALIVE '#'
#define MOSQUITO_DEAD '0'
该部分用来定义宏。这样的定义有助于提高代码的可读性,因为它们可以使代码中出现的特定值更具有表达性。
//初始化每个蚊子的生命值
int healthPoint[20][20] = {0};
for (i = 0;i < m; i ++) {
for (j = 0; j < n; j ++) {
if (grid[i][j] == MOSQUITO_ALIVE) {
healthPoint[i][j] = 2;
}
}
}
该部分定义了一个蚊子生命值整形数组,并初始化为`0`,然后遍历刚刚读入到的`gird` 数组,如果这个地方有蚊子,则在`healthPoint`数组中的对应位置赋值为`2`(默认蚊子共有两滴血,符合题目需要),这样,我们就得到了一个储存了蚊子生命值的数组了
int countMosquitoes = 0;
//一击毙命
if (healthPoint[x][y] != 0) {
healthPoint[x][y] = 0;
grid[x][y] = MOSQUITO_DEAD;
countMosquitoes++;
}
这是处理每一发炮弹杀伤情况的其中一部分代码,对应蚊子被一击毙命的情况。当炮弹的落点上正好有蚊子(`healthPoint[x][y] != 0`),不管这个蚊子是满血还是半血,都被直接击杀,`healthPoint[x][y]`赋值为`0`,然后在`grid`上标记该点蚊子已不存在(` grid[x][y] = MOSQUITO_DEAD;`),最后用于计数杀死蚊子的计数器` countMosquitoes`自增1
if (x - 1 >= 0 && healthPoint[x - 1][y] != 0) {
healthPoint[x - 1][y] -= 1;
if(healthPoint[x - 1][y] == 0) {
grid[x - 1][y] = MOSQUITO_DEAD;
countMosquitoes++;
}
}
这是处理每一发炮弹杀伤情况的另一部分代码,炮弹落点正上方没有蚊子,则检查以炮弹落点为中心的上下左右四个方向是否有蚊子,需要注意,在检查时需要注意即将检查的位置是否超出了`gird`数组的范围,故这里的第一个`if`语句控制了检查的范围。如果这个方向上有蚊子,则蚊子生命值减一(`healthPoint[x - 1][y] -= 1`)。此时,我们还需要多一次判断,用于检查蚊子生命值-1后是否死亡,若死亡,`healthPoint[x - 1][y]`赋值为`0`,然后在`grid`上标记该点蚊子已不存在(` grid[x - 1][y] = MOSQUITO_DEAD;`),最后` countMosquitoes`自增1
后面三个if语句逻辑与上述相同
for(i = 0; i < k; i ++) {
if (i < k - 1)
printf("%d\n", result[i]);
else
printf("%d", result[i]);
}
最后打印`result`中所存储的每一发炮弹的击杀情况,并在最后一行不打印换行符
做题经历:
我在最开始写检查炮弹落点杀伤情况的几个if语句时,混淆了本题的x,y轴,即`x + 1 < m`写成了`x + 1 < n`,`y + 1 < n`写成了`y + 1 < m`,这是因为本题的x,y轴不同于惯性思维。由题给条件,M是二维平面的行,N是二维平面的列,而(0≤x
<M
,0≤y
<N
),则本题该建立的直角坐标系若下图所示: