PTA - 大炮打蚊子|C语言|代码详解|简单易懂|做题经历

题目描述:

现在,我们用大炮来打蚊子:蚊子分布在一个M×N格的二维平面上,每只蚊子占据一格。向该平面的任意位置发射炮弹,炮弹的杀伤范围如下示意:

   O

OXO

   O

其中,X为炮弹落点中心,O为紧靠中心的四个有杀伤力的格子范围。若蚊子被炮弹命中(位于X格),一击毙命,若仅被杀伤(位于O格),则损失一半的生命力。也就是说,一次命中或者两次杀伤均可消灭蚊子。现在给出蚊子的分布情况以及连续k发炮弹的落点,给出每炮消灭的蚊子数。

输入格式:

第一行为两个不超过20的正整数MN,中间空一格,表示二维平面有M行、N列。

接下来M行,每行有N0或者#字符,其中#表示所在格子有蚊子。

接下来一行,包含一个不超过400的正整数k,表示发射炮弹的数量。

最后k行,每行包括一发炮弹的整数坐标xy(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),则本题该建立的直角坐标系若下图所示:

 

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值