kama99 岛屿数量 深搜版
题目
题目描述:
给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。
输入描述:
第一行包含两个整数 N, M,表示矩阵的行数和列数。
后续 N 行,每行包含 M 个数字,数字为 1 或者 0。
输出描述:
输出一个整数,表示岛屿的数量。如果不存在岛屿,则输出 0。
输入示例:
4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1
输出示例:
3
思路
本题思路,是当遇到一个没有遍历过的节点陆地,计数器就加一,然后把该节点陆地所能走到的陆地都标记上。
在后续遇到标记过的陆地节点和海洋节点的时候直接跳过。 这样计数器就是最终岛屿的数量。
所以整体是顺序遍历整个地图,对于一个岛屿,用DFS全部标记上。顺序遍历的方向假设为外层从上到下,内层从左到右。
用深搜三部曲来分析:
- 确认递归函数和参数:图、当前节点索引x, y
- 递归参数:图、当前节点索引x, y
- 全局参数:岛屿计数器count,标记数组flag
- 确认终止条件:走到不合法的节点
- 处理目前搜索节点出发的路径:标记并递归上下左右的陆地
- 标记本节点
- 如果右侧节点是陆地且未标记,对右侧节点递归
- 如果左侧节点是陆地且未标记,对左侧节点递归
- 如果上侧节点是陆地且未标记,取上侧节点递归
- 如果下侧节点是陆地且未标记,取下侧节点递归
解法
import java.util.*;
public class Main{
static int count = 0;
static boolean[][] flag;
static int m;
static int n;
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
m = scanner.nextInt();
n = scanner.nextInt();
int[][] graph = new int[m][n];
flag = new boolean[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
graph[i][j] = scanner.nextInt();
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (graph[i][j] == 1 && !flag[i][j]) {
count++;
dfs(graph, i, j);
}
}
}
System.out.println(count);
}
private static void dfs(int[][] graph, int x, int y) {
flag[x][y] = true;
if (x+1 < m && graph[x+1][y]==1 && !flag[x+1][y]) {
dfs(graph, x+1, y);
}
if (x-1 >= 0 && graph[x-1][y]==1 && !flag[x-1][y]) {
dfs(graph, x-1, y);
}
if (y-1 >= 0 && graph[x][y-1]==1 && !flag[x][y-1]) {
dfs(graph, x, y-1);
}
if (y+1 < n && graph[x][y+1]==1 && !flag[x][y+1]) {
dfs(graph, x, y+1);
}
}
}
kama99 岛屿数量 广搜版
题目
题目描述:
给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。
输入描述:
第一行包含两个整数 N, M,表示矩阵的行数和列数。
后续 N 行,每行包含 M 个数字,数字为 1 或者 0。
输出描述:
输出一个整数,表示岛屿的数量。如果不存在岛屿,则输出 0。
输入示例:
4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1
输出示例:
3
思路
本题思路,是当遇到一个没有遍历过的节点陆地,计数器就加一,然后把该节点陆地所能走到的陆地都标记上。
在后续遇到标记过的陆地节点和海洋节点的时候直接跳过。 这样计数器就是最终岛屿的数量。
所以整体是顺序遍历整个地图,对于一个岛屿,用BFS全部标记上。顺序遍历的方向假设为外层从上到下,内层从左到右。
BFS思路:
- 从一个没有遍历过的节点陆地进入BFS
- 新建队列,把初始节点加入队列,节点标记已访问
- 当队列非空
- 取队列头,把它上下左右所有未访问的陆地节点标记已访问,并加入队列
解法
import java.util.*;
public class Main{
static int count = 0;
static boolean[][] flag;
static int m;
static int n;
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
m = scanner.nextInt();
n = scanner.nextInt();
int[][] graph = new int[m][n];
flag = new boolean[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
graph[i][j] = scanner.nextInt();
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (graph[i][j] == 1 && !flag[i][j]) {
count++;
bfs(graph, i, j);
}
}
}
System.out.println(count);
}
private static void bfs(int[][] graph, int a, int b) {
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[]{a, b});
flag[a][b] = true;
while (!queue.isEmpty()) {
int[] node = queue.poll();
int x = node[0];
int y = node[1];
if (x+1 < m && graph[x+1][y]==1 && !flag[x+1][y]) {
flag[x+1][y] = true;
queue.add(new int[]{x+1,y});
}
if (x-1 >= 0 && graph[x-1][y]==1 && !flag[x-1][y]) {
flag[x-1][y] = true;
queue.add(new int[]{x-1,y});
}
if (y-1 >= 0 && graph[x][y-1]==1 && !flag[x][y-1]) {
flag[x][y-1] = true;
queue.add(new int[]{x,y-1});
}
if (y+1 < n && graph[x][y+1]==1 && !flag[x][y+1]) {
flag[x][y+1] = true;
queue.add(new int[]{x,y+1});
}
}
}
}
kama100 岛屿的最大面积
题目
题目描述
给定一个由 1(陆地)和 0(水)组成的矩阵,计算岛屿的最大面积。岛屿面积的计算方式为组成岛屿的陆地的总数。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。
输入描述
第一行包含两个整数 N, M,表示矩阵的行数和列数。后续 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述
输出一个整数,表示岛屿的最大面积。如果不存在岛屿,则输出 0。
输入示例
4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1
输出示例
4
思路
本题思路和上题相似,当遇到一个没有遍历过的节点陆地,就进入遍历流程,摸清此节点可以到达的陆地面积并标记访问过。全程取最大的面积就得到结果。
所以整体是顺序遍历整个地图,对于一个岛屿,用BFS/DFS全部标记上。顺序遍历的方向假设为外层从上到下,内层从左到右。
解法
import java.util.*;
public class Main{
static int m;
static int n;
static boolean[][] flag;
static int max = 0;
static int area = 0;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
m = scanner.nextInt();
n = scanner.nextInt();
int[][] graph = new int[m][n];
flag = new boolean[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
graph[i][j] = scanner.nextInt();
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (graph[i][j] == 1 && !flag[i][j]) {
area = 1;
dfs(graph, i, j);
max = Math.max(max, area);
}
}
}
System.out.println(max);
}
private static void dfs(int[][] graph, int x, int y) {
flag[x][y] = true;
if (x+1 < m && graph[x+1][y]==1 && !flag[x+1][y]) {
area++;
dfs(graph, x+1, y);
}
if (x-1 >= 0 && graph[x-1][y]==1 && !flag[x-1][y]) {
area++;
dfs(graph, x-1, y);
}
if (y-1 >= 0 && graph[x][y-1]==1 && !flag[x][y-1]) {
area++;
dfs(graph, x, y-1);
}
if (y+1 < n && graph[x][y+1]==1 && !flag[x][y+1]) {
area++;
dfs(graph, x, y+1);
}
}
}
今日收获总结
岛屿问题的中心就是,一个岛,不论从哪个发现,都应该能按照构成岛屿的规则遍历玩这个岛。由此可以得到岛屿的相关信息。