ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

蓝桥杯真题 全球变暖【第九届】【省赛】【B组】(C语言实现)保姆题解

2022-03-20 15:33:19  阅读:207  来源: 互联网

标签:XZ sz gs 真题 int 题解 hang 蓝桥 lie


资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

  你有一张某海域NxN像素的照片,"."表示海洋、"#"表示陆地,如下所示:

  .......
  .##....
  .##....
  ....##.
  ..####.
  ...###.
  .......

  其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。

  由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。

  例如上图中的海域未来会变成如下样子:

  .......
  .......
  .......
  .......
  ....#..
  .......
  .......

  请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。

输入格式

  第一行包含一个整数N。 (1 <= N <= 1000)
  以下N行N列代表一张海域照片。

  照片保证第1行、第1列、第N行、第N列的像素都是海洋。

输出格式

  一个整数表示答案。

样例输入

7
.......
.##....
.##....
....##.
..####.
...###.
.......

样例输出

1

本人思路:

通过一个二维数组来存储整片海域 , 每个元素中需要记录是陆地还是海洋,然后还需要记录这个小岛的编号和标记是否该被淹没,也就是说,得用三维数组来存储。

每个元素可以以三个信息来表示:

#include <stdio.h>
enum
{
	XZ = 0,//表示存储'.'或'#' 的下标 
	ZT = 1,//表示存储当前被淹没还是没被淹没的下标 
	BH = 2,//表示小岛编号的下标 
	YM = 3,//表示小岛被淹没(Yan Mo) 
	BL = 4,//表示小岛没被淹没,也就是保留(Bao Liu) 
};

我们用enum来表示下标和标记(这样好看一些)

	int N;//海域大小 
	scanf("%d" , &N);
	char hai_lu[N][N][3];//定义三维数组,储存信息 

接下来是输入:

注意,这里是字符串的输入所以可能会读到换行符,所以我用了getchar()函数来一个一个读取,记得给其他的元素初始化

void shuru(int gs , char sz[][gs][3])
{
	int i , j;
	for(i = 0;i < gs;i ++)
	{
		for(j = 0;j < gs;j ++)
		{
			char temp;
			while(temp = getchar() , temp == '\n')//如果读到换行符,就继续读入,直到不是换行符
			{
				continue;
			}
			sz[i][j][XZ] = temp;
			sz[i][j][ZT] = 0;//状态初始化
			sz[i][j][BH] = 0;//编号初始化
		}
	}
}

数出这片海域中小岛个数,然后模拟淹没小岛,再数出淹没后小岛个数。

如何数出小岛:

定义一个计数的变量,然后遍历三维数组(其实本质是二维)。第一层判断,当前元素是否是‘#’字符;第二层判断,这个位置的元素是否已经被标记了是否该被淹没(如果被标记了就代表它是和其他‘#’字符连在一起的组成一个岛,故不用加入计数)。若两层都能通过,则计数器加一。

int shu_dao(int gs , char sz[][gs][3])
{
	int jishu = 1;//计数,同时也充当对每个小岛的编号 
	int i , j;
	for(i = 1;i < gs - 1;i ++)//遍历数组 
	{
		for(j = 1;j < gs - 1;j ++)
		{
			if(sz[i][j][XZ] == '#')//第一层判断 看看是否是‘#’
			{
				if(sz[i][j][ZT] == 0)//第二层判断 看看是否已经被标记了
				{
					biaoji(i , j , gs , sz , jishu);//找当前元素的上下左右是否也能被标记 
					jishu ++;
				}
			}
		}
	}
	return jishu - 1;//因为是从1开始计数,所以需要减一 
}

同时!!!(重点):以这一个元素为起点,向它位置的上,下,左,右进行搜索,看看是否有‘#’字符,有则对其进行判断。

判断什么?由题意可以知道,小岛怎样才能被淹没,当块陆地的上下左右任意方向出现了海洋,也就是‘.’字符,就能被淹没,然后被标记上淹没。反之,当上下左右任意方向都是‘#’字符,则代表它的周围都是陆地,也就意味着它不会被淹没,此时给它标记上不淹没。

void biaoji(int hang , int lie , int gs , char sz[][gs][3] , int bd)
{
	sz[hang][lie][BH] = bd;//将这一块岛屿进行编号,编号来自于计数个数,计数为1,则为一号岛屿,编号为1,以此类推。计数和编号是同步进行的 
	if(sz[hang - 1][lie][XZ] == '#' && sz[hang + 1][lie][XZ] == '#' && sz[hang][lie - 1][XZ] == '#' && sz[hang][lie + 1][XZ] == '#')
	{
		sz[hang][lie][ZT] = BL;//如果这个元素的上下左右均为'#',则把它标记成BL 
	}
	else
	{
		sz[hang][lie][ZT] = YM;//如果不是,则把它标记成YM 
	}
	
	if(sz[hang - 1][lie][XZ] == '#' && sz[hang - 1][lie][ZT] == 0)//继续向上方搜索 
	{
		biaoji(hang - 1 , lie , gs , sz , bd);
	}
	if(sz[hang + 1][lie][XZ] == '#' && sz[hang + 1][lie][ZT] == 0)//继续向下方搜索 
	{
		biaoji(hang + 1 , lie , gs , sz , bd);
	}
	if(sz[hang][lie - 1][XZ] == '#' && sz[hang][lie - 1][ZT] == 0)//继续向左方搜索 
	{
		biaoji(hang , lie - 1 , gs , sz , bd);
	}
	if(sz[hang][lie + 1][XZ] == '#' && sz[hang][lie + 1][ZT] == 0)//继续向右方搜索 
	{
		biaoji(hang , lie + 1 , gs , sz , bd);
	}
}

淹没!我们只需要再遍历一遍,这个三维数组,看看哪些是陆地,同时被标记上了淹没(YM)的元素;把它们统统换成‘.’就行了。这样,淹没后的海域做出来了。

接着,就是再淹没后的海域中数小岛的个数。用的方法和上述类似,但是,我们不是还给每个小岛编号了吗,这就用起来。

我们可以定义一个一维数组,长度为小岛的总数,全部元素初始化成0。每个小岛的编号作为这个数组的下标。接着再遍历一边数组,如果我们遇到了‘#’,同时它被标记为了保留(BL)时,我们可以将它的编号作为这个一维数组的下标,将它改为1。

int qiu_ym_gs(int d_gs , int gs , char sz[][gs][3])
{
	int d_bh[d_gs];//创建一个一维数组 
	chushihua(d_gs , d_bh);//初始化,全为0 
	
	int i , j;
	for(i = 1;i < gs - 1;i ++)//遍历这个三维数组 
	{
		for(j = 1;j < gs - 1;j ++)
		{
			if(sz[i][j][XZ] == '#')//看看它是否为'#' 
			{
				if(sz[i][j][ZT] == BL)//看看它是否保留 
				{
					d_bh[sz[i][j][BH] - 1] = 1;//都满足了,就把一维数组的这个位置变成1(也就是说这个小岛没有被全部淹没) 
				}//注意,数组下标我时从0开始的,所以这边编号减去了1; 
			}
		}
	}
	return tongji(d_gs , d_bh);//最后统计一下这个一维数组里有多少个0就行了 
}

统计一下一维数组

int tongji(int gs , int sz[])
{
	int jishu = 0;//计数
	int i;
	for(i = 0;i < gs;i ++)
	{
		jishu += sz[i] == 0;//看看这个编号下的小岛还在不在,这里相当于条件判断,真为1,假为0
	}
	return jishu;
}

完成,输出就行了

附上完整代码:

#include <stdio.h>
enum
{
	XZ = 0,//表示存储'.'或'#' 的下标 
	ZT = 1,//表示存储当前被淹没还是没被淹没的下标 
	BH = 2,//表示小岛编号的下标 
	YM = 3,//表示小岛被淹没(Yan Mo) 
	BL = 4,//表示小岛没被淹没,也就是保留(Bao Liu) 
};
void shuru(int gs , char [][gs][3]);
int shu_dao(int gs , char [][gs][3]);
void biaoji(int , int , int gs , char [][gs][3] , int);
void yanmo(int gs , char [][gs][3]);
int qiu_ym_gs(int , int gs , char [][gs][3]);
void chushihua(int , int []);
int tongji(int , int []);
int main (void)
{
	int N;//海域大小 
	scanf("%d" , &N);
	char hai_lu[N][N][3];//定义三维数组,储存信息 
	shuru(N , hai_lu);
	int dao_gs = shu_dao(N , hai_lu);
	yanmo(N , hai_lu);
	printf("%d\n" , qiu_ym_gs(dao_gs , N , hai_lu));
	return 0;
}

int tongji(int gs , int sz[])
{
	int jishu = 0;
	int i;
	for(i = 0;i < gs;i ++)
	{
		jishu += sz[i] == 0;
	}
	return jishu;
}

void chushihua(int gs , int sz[])
{
	while(gs -- > 0)
	{
		*sz ++ = 0;
	}
}

int qiu_ym_gs(int d_gs , int gs , char sz[][gs][3])
{
	int d_bh[d_gs];//创建一个一维数组 
	chushihua(d_gs , d_bh);//初始化,全为0 
	
	int i , j;
	for(i = 1;i < gs - 1;i ++)//遍历这个三维数组 
	{
		for(j = 1;j < gs - 1;j ++)
		{
			if(sz[i][j][XZ] == '#')//看看它是否为'#' 
			{
				if(sz[i][j][ZT] == BL)//看看它是否保留 
				{
					d_bh[sz[i][j][BH] - 1] = 1;//都满足了,就把一维数组的这个位置变成1(也就是说这个小岛没有被全部淹没) 
				}//注意,数组下标我时从0开始的,所以这边编号减去了1; 
			}
		}
	}
	return tongji(d_gs , d_bh);//最后统计一下这个一维数组里有多少个0就行了 
}

void yanmo(int gs , char sz[][gs][3])
{
	int i , j;
	for(i = 1;i < gs - 1;i ++)
	{
		for(j = 1;j < gs - 1;j ++)
		{
			if(sz[i][j][ZT] == YM)
			{
				sz[i][j][XZ] = '.';
			}
		}
	}
}

void biaoji(int hang , int lie , int gs , char sz[][gs][3] , int bd)
{
	sz[hang][lie][BH] = bd;//将这一块岛屿进行编号,编号来自于计数个数,计数为1,则为一号岛屿,编号为1,以此类推。计数和编号是同步进行的 
	if(sz[hang - 1][lie][XZ] == '#' && sz[hang + 1][lie][XZ] == '#' && sz[hang][lie - 1][XZ] == '#' && sz[hang][lie + 1][XZ] == '#')
	{
		sz[hang][lie][ZT] = BL;//如果这个元素的上下左右均为'#',则把它标记成BL 
	}
	else
	{
		sz[hang][lie][ZT] = YM;//如果不是,则把它标记成YM 
	}
	
	if(sz[hang - 1][lie][XZ] == '#' && sz[hang - 1][lie][ZT] == 0)//继续向上方搜索 
	{
		biaoji(hang - 1 , lie , gs , sz , bd);
	}
	if(sz[hang + 1][lie][XZ] == '#' && sz[hang + 1][lie][ZT] == 0)//继续向下方搜索 
	{
		biaoji(hang + 1 , lie , gs , sz , bd);
	}
	if(sz[hang][lie - 1][XZ] == '#' && sz[hang][lie - 1][ZT] == 0)//继续向左方搜索 
	{
		biaoji(hang , lie - 1 , gs , sz , bd);
	}
	if(sz[hang][lie + 1][XZ] == '#' && sz[hang][lie + 1][ZT] == 0)//继续向右方搜索 
	{
		biaoji(hang , lie + 1 , gs , sz , bd);
	}
}

int shu_dao(int gs , char sz[][gs][3])
{
	int jishu = 1;//计数,同时也充当对每个小岛的编号 
	int i , j;
	for(i = 1;i < gs - 1;i ++)//遍历数组 
	{
		for(j = 1;j < gs - 1;j ++)
		{
			if(sz[i][j][XZ] == '#')//第一层判断 
			{
				if(sz[i][j][ZT] == 0)//第二层判断 
				{
					biaoji(i , j , gs , sz , jishu);//找当前元素的上下左右是否也能被标记 
					jishu ++;
				}
			}
		}
	}
	return jishu - 1;//因为是从1开始计数,所以需要减一 
}

void shuru(int gs , char sz[][gs][3])
{
	int i , j;
	for(i = 0;i < gs;i ++)
	{
		for(j = 0;j < gs;j ++)
		{
			char temp;
			while(temp = getchar() , temp == '\n')
			{
				continue;
			}
			sz[i][j][XZ] = temp;
			sz[i][j][ZT] = 0;
			sz[i][j][BH] = 0;
		}
	}
}

真的会有人看这么多吗

标签:XZ,sz,gs,真题,int,题解,hang,蓝桥,lie
来源: https://blog.csdn.net/qq_66013425/article/details/123612693

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有