蓝桥杯真题 全球变暖【第九届】【省赛】【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