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

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

作者:互联网

资源限制

时间限制: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