题目描述
你有一张某海域 N * N像素的照片,`.` 表示海洋、 `#` 表示陆地,如下所示:
.......
.##....
.##....
....##.
..####.
...###.
.......
其中 "上下左右" 四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 2 座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
```
.......
.......
.......
.......
....#..
.......
.......
```
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
输入格式
第一行包含一个整数 N。
以下 N行 N 列代表一张海域照片。
照片保证第 1 行、第 1列、第 N 行、第 N 列的像素都是海洋。
输出格式
一个整数表示答案。
这题可以用DFS和bfs
用bfs写
#include <stdio.h>
#include <string.h>
#define N 1005
char a[N][N]; // 地图数组
int n, vis[N][N], dir[4][2] = { {-1,0},{0,-1},{0,1},{1,0} }; // vis数组用于标记是否访问过,dir数组表示上下左右四个方向
struct Point // 定义一个坐标结构体
{
int x, y;
};
struct Point q[1000000]; // 定义一个坐标队列
// BFS算法,从x,y坐标出发进行搜索
int bfs(int x, int y)
{
struct Point p;
p.x = x; p.y = y;
int front = 0, rear = 0; // 队列的头尾指针
q[rear++] = p; // 初始坐标入队
int left = 0; // 表示一个连通块中留下的没有被淹没的陆地像素
while (front < rear) // 队列非空时循环
{
p = q[front++]; // 出队一个坐标
int i, cnt = 0;
for (i = 0; i < 4; i++) // 遍历上下左右四个方向
{
int dx = p.x + dir[i][0];
int dy = p.y + dir[i][1];
if (dx < 0 || dx >= n || dy < 0 || dy >= n) // 如果出界则跳过
continue;
if (a[dx][dy] == '#') // 如果是陆地
{
cnt++; // 统计周围陆地数量
if (!vis[dx][dy]) // 如果未访问过
{
vis[dx][dy] = 1; // 标记为已访问
q[rear].x = dx; // 入队
q[rear].y = dy;
rear++;
}
}
}
if (cnt == 4) // 如果一个陆地像素的上下左右四个方向也是陆地像素
left++; // 这个陆地像素肯定不会被淹没,留下了
}
return left; // 返回留下的陆地像素数量
}
int main()
{
int i, j, ans = 0;
scanf("%d", &n); // 输入地图大小
for (i = 0; i < n; i++)
{
scanf("%s", a[i]); // 输入地图内容
}
memset(vis, 0, sizeof(vis)); // 初始化访问数组
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
if (a[i][j] == '#' && !vis[i][j]) // 从这个没有访问过的陆地像素出发寻找其连通块
{
vis[i][j] = 1; // 标记为已访问
if (!bfs(i, j)) // 包含(i,j)陆地像素的连通块中的陆地像素全部被淹没,left=0
ans++; // 被淹没的岛屿个数加 1
}
}
}
printf("%d\n", ans); // 输出结果
return 0;
}
思路:
-
遍历地图的每个位置,对于每个位置,如果当前位置是陆地(即
a[i][j] == '#'
),则进行 BFS。 -
在 BFS 中,定义一个队列
q
,用于存储待访问的坐标。将当前位置的坐标入队,并标记为已访问。 -
在队列不为空的情况下,执行 BFS 操作:出队一个坐标,遍历其上下左右四个相邻位置,如果该相邻位置是陆地且未被访问过,则将其标记为已访问,并入队。
-
如果一个陆地像素的上下左右四个方向都是陆地像素,即周围陆地数量为 4,则该陆地像素不会被淹没,留下来。
-
最终,遍历所有未访问过的陆地像素,并将每个未访问过的陆地像素作为 BFS 的起点,统计被淹没的陆地的数量
用dfs写
#include <stdio.h>
int n, cnt, sum, ans, t; // 定义变量n表示地图大小,cnt表示周围陆地数量,sum表示陆地块数量,ans表示被淹没的陆地块数量,t表示标记是否有被淹没的陆地块
int dx[] = { 0, 1, 0, -1 }; // x方向移动的增量
int dy[] = { 1, 0, -1, 0 }; // y方向移动的增量
char mp[1010][1010]; // 地图数组
void dfs(int x, int y) {
if (!t) { // 如果t为0,说明当前块尚未判断是否被淹没
cnt = 0;
for (int i = 0; i < 4; i++) {
if (mp[x + dx[i]][y + dy[i]] != '.') { // 判断当前位置周围是否有陆地
cnt++;
}
}
if (cnt == 4) { // 如果周围都是陆地
ans++; // 当前块被不淹没
t = 1; // 标记该块不被淹没
}
}
mp[x][y] = '*'; // 将当前块标记为已访问过
for (int i = 0; i < 4; i++) { // 遍历上下左右四个方向
int xx = x + dx[i];
int yy = y + dy[i];
if (xx < 0 || xx >= n || yy < 0 || yy >= n || mp[xx][yy] != '#') { // 判断是否出界或者是否是海洋
continue;
}
dfs(xx, yy); // 递归调用dfs函数
}
}
int main() {
scanf("%d", &n); // 输入地图大小
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
scanf(" %c", &mp[i][j]); // 输入地图内容
}
}
for (int i = 1; i < n - 1; i++) {
for (int j = 1; j < n - 1; j++) {
if (mp[i][j] == '#') { // 如果当前位置是陆地
sum++; // 统计陆地块数量
t = 0; // 初始化t为0
dfs(i, j); // 深度优先搜索,判断该块是否被淹没
}
}
}
printf("%d\n", sum - ans); // 输出结果:总陆地块数减去没被淹没的陆地块数
return 0;
}