《啊哈,算法》第三章枚举!很暴力 第二节炸弹人

题目:

炸弹人:现有一个特殊的关卡:游戏者只有一枚炸弹,且炸弹杀伤距离超长,可以消灭杀伤范围内所有敌人。请问炸弹放在哪个位置才可以消灭最多的敌人(炸弹只能放在空地上)。

输入样例:

13 13
#############
#GG.GGG#GGG.#
###.#G#G#G#G#
#…#…G#
#G#.###.#G#G#
#GG.GGG.#.GG#
#G#.#G#.#.###
##G…G…#
#G#.#G###.#G#
#…G#GGG.GG#
#G#.#G#G#.#G#
#GG.GGG#G.GG#
#############

输出样例:

将炸弹放置在(9,9),最多可消灭8个敌人

书中给的代码:

#include<stdio.h>
int main(){
	char a[20][21];//假设这里的地图大小不超过20*20
	int i,j,x,y,n,m,p,q,sum,map =0;
	scanf("%d%d",&n,&m);//读入n和m,n表示有多少行字符,m表示每行有多少列
	//读入n行字符
	for(i =0;i <=n-1;i++){
		scanf("%s",a[i]);
	}
	//用两重循环枚举地图中的每一点
	for(i =0;i <=n-1;i++){
		for(j =0;j <=m-1;j++){//首先判断这个点是不是平地,是平地才可以被放置炸弹
			if(a[i][j] =='.'){
				sum =0;//sum用来计数(可以消灭的敌人数),所以需要初始化为零
				//将当前坐标i,j复制到两个新变量x、y中,以便向上下左右四个方向分别统计可以消灭的敌人数
				//向上统计可以消灭的敌人数
				x =i;
				y =j;
				while(a[x][y] !='#'){//判断是不是墙,如果不是墙就继续
				    //如果当前点是敌人,则进行计数
					if(a[x][y] =='G'){
						sum++;
					}
					//x--的作用是继续向上统计
					x--;
				}
				//向下统计可以消灭的敌人数
				x =i;
				y =j;
				while(a[x][y] !='#'){
					if(a[x][y] =='G'){
						sum++;
					}
					//x++的作用是继续向下统计
					x++;					
				}
				//向左统计可以消灭的敌人数
				x =i;
				y =j;
				while(a[x][y] !='#'){
					if(a[x][y] =='G'){
						sum++;
					}
					//y--的作用是继续向左统计
					y--;
				}
				//向左统计可以消灭的敌人数
				x =i;
				y =j;
				while(a[x][y] !='#'){
					if(a[x][y] =='G'){
						sum++;
					}
					//y++的作用是继续向右统计
			 		y++;
				}
				//更新map的值
				if(sum >map){
					map =sum;//如果当前点所能消灭的敌人的总数大于map,则更新map
					//并用p和q记录当前点的坐标
					p =i;
					q =j;
				}
			}
		}
	}
	printf("将炸弹放置在(%d,%d),最多可消灭%d个敌人\n",p,q,map);
	getchar();getchar();
	return 0;
}

该代码中首先用一个二维字符数组来存储这个地图,并将地图模型化。墙用表示;敌人用表示;空地用.表示。在读入地图时代码中选择使用for循环加%s的方式,即输入字符串到a[i]行,从a[i]行的首地址开始存放;如果我们不选择用这种方式存放地图,而选择使用两层for循环加%c一个字符一个字符的存放呢?
那首先,我们先来看以一下C语言二维字符数组的一些相关知识以及%s和%c的区别。
二维字符数组一般用于存储和处理多个字符串,二维字符数组中的每一行均可存储表示一个字符串。
二维字符数组的定义:
二维字符数组的定义格式为:char 数组名[第一维大小][第二维大小];

如:

char a[3][10];//定义了一个3行10列的二维字符数组a

【例 1】 分析以下程序,输出其运行结果。

#include<stdio.h>
int main (){
	char a[3][7] ={"Apple","Orange","Pear"};
	int i;
	for(i =0;i <3;i++){
		printf ("%s\n",a[i]);	
	}
	return 0;
}

该数组各元素中的值如下所示:

0123456
a[0]Apple\0\0
a[1]Orange\0
a[2]Pear\0\0\0

printf ("%s\n",c[0]); //输出Apple
printf ("%s\n",c[1]); //输出Orange
printf ("%s\n",c[2]); //输出Pear
运行结果:
在这里插入图片描述
以下均是对二维字符数组元素的合法引用:
char a[][7]={“Apple”,“Orange”,“Pear”};

  1. printf ("%c",a[1][4]); //输出2行5列元素’g’字符
  2. scanf ("%c",&a[2][3]);//存放一个字符到3行4列元素中
  3. a[2][0]=‘P’; //把字符赋值给3行1列元素
  4. printf ("%s",a[1]);//a[1]为第2行的数组名(首元素地址)输出Orange
  5. scanf ("%s",a[2]);//存放字符串到a[2]行,从a[2]行的首地址开始存放

字符数组的输入除了使用scanf外,还可以使用getchar或gets;其输出除了使用printf外,还可以使用putchar或puts。

scanf输入与printf输出:scanf和printf对字符类型有%c和%s两种格式,其中%c用来输入单个字符,%s用来输入一个字符串并存在字符数组里;%c格式能够识别空格与换行符并将其输入,而%s通过换行符或空格来识别一个字符串的结束。

#include<stdio.h>
int main(){
    char a[10];
    scanf("%s",a);//scanf中%s输入通过空格或者换行识别字符串的结束
    printf("%s",a);
    return 0;
}

运行结果:
在这里插入图片描述

#include<stdio.h>
int main(){
    char c1,c2,c3;
    scanf("%c%c%c",&c1,&c2,&c3);
    printf("%c %c %c\n",c1,c2,c3); 
	return 0;
}

运行结果:
在这里插入图片描述
在这里插入图片描述

#include<stdio.h>
int main(){
    char c1,c2,c3;
    scanf("%c %c %c",&c1,&c2,&c3);
    printf("%c %c %c\n",c1, c2, c3);
    return 0;
}

运行结果:
在这里插入图片描述
以上两种情况,都输入a b c,但运行结果却不一样。因为示例1中,scanf的%c格式可以识别空格和换行并将其输入。那示例2为什么又可以了呢?因为scanf里“ ”内的东西表示格式。

getchar输入与putchar输出:getchar与putchar分别用来输入和输出单个字符,都能够识别空格和换行。

#include<stdio.h>
int main(){
    char a[5][5];
    for(int i =0;i <3;i++){
	    for(int j =0;j <3;j++){
			a[i][j] =getchar();//这里的作用与下句一样
			//scanf("%c",&a[i][j]);
		}
		getchar();//为了把输入中每行末尾的换行符吸收掉
	}
	printf("----------------------\n");
	for(int i =0;i <3;i++){
		for(int j =0;j <3;j++){
			putchar(a[i][j]);//这里的作用与下句一样
			//printf("%c",a[i][j]);
		}
		putchar('\n');
	}
    return 0;
}

运行结果:
在这里插入图片描述

gets输入与puts输出:gets用来输入一行字符串(注意:gets识别换行符\n作为输入结束,因此scanf完一个整数后,如果要使用gets,需要先用getchar接收整数后的换行符),并将其存放于一维数组或二维数组中的一维中;puts用来输出一行字符串,即将一维数组(或二维数组的一维)在界面上输出,并紧跟一个换行

#include<stdio.h>
int main(){
	char a1[20];
	char a2[5][10];
	int i;
	printf("输入字符串存入一维数组中:\n");
	gets(a1);
	printf("输入3个字符串分别存入二维数组的一维中:\n");
	for (i = 0; i < 3; i++){
		gets(a2[i]);
	}
	printf("一维数组a1:\n");
	puts(a1);
	printf("二维数组a2:\n");
	for (i = 0; i < 3; i++){
		puts(a2[i]);
	}
	return 0;
 } 

运行结果:
在这里插入图片描述
现在,我们已经了解了%s和%d的输入输出区别,我们再用两层for循环加%c一个字符一个字符的存放炸弹人的地图试试。

#include<stdio.h>
int main(){
	char a[20][21];
	int i,j,x,y,n,m,p,q,sum,map =0;
	scanf("%d%d",&n,&m);
	getchar();//吸收在输入样例中的n,m时后面敲入的回车,否则会被%c识别并存入地图中
	for(i =0;i <n;i++){
		for(j =0;j <m;j++){
			scanf("%c",&a[i][j]);//这里的作用与下一句一样
			//a[i][j] =getchar();
		}
		getchar();
	}
	for(i =0;i <n;i++){
		for(j =0;j <m;j++){
			if(a[i][j] =='.'){
				sum =0;
				x =i;
				y =j;
				while(a[x][y] !='#'){
					if(a[x][y] =='G'){
						sum++;
					}
					x--;
				}
				x =i;
				y =j;
				while(a[x][y] !='#'){
					if(a[x][y] =='G'){
						sum++;
					}
					x++;					
				}
				x =i;
				y =j;
				while(a[x][y] !='#'){
					if(a[x][y] =='G'){
						sum++;
					}
					y--;
				}
				x =i;
				y =j;
				while(a[x][y] !='#'){
					if(a[x][y] =='G'){
						sum++;
					}
			 		y++;
				}
				if(sum >map){
					map =sum;
					p =i;
					q =j;
				}
			}
		}
	}
	printf("将炸弹放置在(%d,%d),最多可消灭%d个敌人\n",p,q,map);
	getchar();getchar();
	return 0;
}

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值