当前位置: 首页 > news >正文

算法训练营day51 图论② 岛屿数量深搜、广搜、最大面积

        图论的第二篇博客,岛屿问题!主要了解两种最基本的遍历方法。同时在图论的部分,需要更加熟悉ACM模式的编程

岛屿数量深搜

        本题思路,是用遇到一个没有遍历过的节点陆地,计数器就加一,然后把该节点陆地所能遍历到的陆地都标记上。在遇到标记过的陆地节点和海洋节点的时候直接跳过。 这样计数器就是最终岛屿的数量。

        所以深度搜索的部分在于把同一片陆地上的节点全部标记,这个是深度搜索在这道题中的作用

版本一

direction = [[0, 1], [1, 0], [0, -1], [-1, 0]]  # 四个方向:上、右、下、左def dfs(grid, visited, x, y):"""对一块陆地进行深度优先遍历并标记"""for i, j in direction:next_x = x + inext_y = y + j# 下标越界,跳过if next_x < 0 or next_x >= len(grid) or next_y < 0 or next_y >= len(grid[0]):continue# 未访问的陆地,标记并调用深度优先搜索if not visited[next_x][next_y] and grid[next_x][next_y] == 1:visited[next_x][next_y] = Truedfs(grid, visited, next_x, next_y)if __name__ == '__main__':  # 版本一n, m = map(int, input().split())# 邻接矩阵grid = []for i in range(n):grid.append(list(map(int, input().split())))# 访问表visited = [[False] * m for _ in range(n)]res = 0for i in range(n):for j in range(m):# 判断:如果当前节点是陆地,res+1并标记访问该节点,使用深度搜索标记相邻陆地。if grid[i][j] == 1 and not visited[i][j]:res += 1visited[i][j] = Truedfs(grid, visited, i, j)print(res)

版本二

        和上一个版本区别在于递归调用结束判断的部分,这个细节需要对于深度搜索的熟练度和理解

direction = [[0, 1], [1, 0], [0, -1], [-1, 0]]  # 四个方向:上、右、下、左def dfs(grid, visited, x, y):"""对一块陆地进行深度优先遍历并标记"""# 与版本一的差别,在调用前增加判断终止条件if visited[x][y] or grid[x][y] == 0:returnvisited[x][y] = Truefor i, j in direction:next_x = x + inext_y = y + j# 下标越界,跳过if next_x < 0 or next_x >= len(grid) or next_y < 0 or next_y >= len(grid[0]):continue# 由于判断条件放在了方法首部,此处直接调用dfs方法dfs(grid, visited, next_x, next_y)if __name__ == '__main__':# 版本二n, m = map(int, input().split())# 邻接矩阵grid = []for i in range(n):grid.append(list(map(int, input().split())))# 访问表visited = [[False] * m for _ in range(n)]res = 0for i in range(n):for j in range(m):# 判断:如果当前节点是陆地,res+1并标记访问该节点,使用深度搜索标记相邻陆地。if grid[i][j] == 1 and not visited[i][j]:res += 1dfs(grid, visited, i, j)print(res)

岛屿数量广搜

        仍然是一样的计数思路

代码实现

        这个地方和深度搜索中的区别在于:这里使用了队列,而深度搜索使用的是递归

from collections import deque
directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]
def bfs(grid, visited, x, y):que = deque([])que.append([x,y])visited[x][y] = Truewhile que:cur_x, cur_y = que.popleft()for i, j in directions:next_x = cur_x + inext_y = cur_y + jif next_y < 0 or next_x < 0 or next_x >= len(grid) or next_y >= len(grid[0]):continueif not visited[next_x][next_y] and grid[next_x][next_y] == 1: visited[next_x][next_y] = Trueque.append([next_x, next_y])def main():n, m = map(int, input().split())grid = []for i in range(n):grid.append(list(map(int, input().split())))visited = [[False] * m for _ in range(n)]res = 0for i in range(n):for j in range(m):if grid[i][j] == 1 and not visited[i][j]:res += 1bfs(grid, visited, i, j)print(res)if __name__ == "__main__":main()

超时写法

        没有在首次入队列的时候标记陆地,导致每个陆地都会进入到队列中,如果标记了,会减少很多节点的入队列,来提升效率

        需要注意的是,其实这里的超时问题和深度搜索中的结束判断的内在逻辑是一样的,是由搜索逻辑仅处理后续节点 还是 处理本节点以及后续节点(全部)的选择  

int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
void bfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {queue<pair<int, int>> que;que.push({x, y});while(!que.empty()) {pair<int ,int> cur = que.front(); que.pop();int curx = cur.first;int cury = cur.second;visited[curx][cury] = true; // 从队列中取出在标记走过for (int i = 0; i < 4; i++) {int nextx = curx + dir[i][0];int nexty = cury + dir[i][1];if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;  // 越界了,直接跳过if (!visited[nextx][nexty] && grid[nextx][nexty] == '1') {que.push({nextx, nexty});}}}}

岛屿最大面积

        增加一个计数器就可以了,基本内容还是上面两种方法

        DFS(深度搜索)

# 四个方向
position = [[0, 1], [1, 0], [0, -1], [-1, 0]]
count = 0def dfs(grid, visited, x, y):"""深度优先搜索,对一整块陆地进行标记"""global count  # 定义全局变量,便于传递count值for i, j in position:cur_x = x + icur_y = y + j# 下标越界,跳过if cur_x < 0 or cur_x >= len(grid) or cur_y < 0 or cur_y >= len(grid[0]):continueif not visited[cur_x][cur_y] and grid[cur_x][cur_y] == 1:visited[cur_x][cur_y] = Truecount += 1dfs(grid, visited, cur_x, cur_y)n, m = map(int, input().split())
# 邻接矩阵
grid = []
for i in range(n):grid.append(list(map(int, input().split())))
# 访问表
visited = [[False] * m for _ in range(n)]result = 0  # 记录最终结果
for i in range(n):for j in range(m):if grid[i][j] == 1 and not visited[i][j]:count = 1visited[i][j] = Truedfs(grid, visited, i, j)result = max(count, result)print(result)

        BFS(广度搜索)

from collections import dequeposition = [[0, 1], [1, 0], [0, -1], [-1, 0]]  # 四个方向
count = 0def bfs(grid, visited, x, y):"""广度优先搜索对陆地进行标记"""global count  # 声明全局变量que = deque()que.append([x, y])while que:cur_x, cur_y = que.popleft()for i, j in position:next_x = cur_x + inext_y = cur_y + j# 下标越界,跳过if next_x < 0 or next_x >= len(grid) or next_y < 0 or next_y >= len(grid[0]):continueif grid[next_x][next_y] == 1 and not visited[next_x][next_y]:visited[next_x][next_y] = Truecount += 1que.append([next_x, next_y])n, m = map(int, input().split())
# 邻接矩阵
grid = []
for i in range(n):grid.append(list(map(int, input().split())))
visited = [[False] * m for _ in range(n)]  # 访问表result = 0  # 记录最终结果
for i in range(n):for j in range(m):if grid[i][j] == 1 and not visited[i][j]:count = 1visited[i][j] = Truebfs(grid, visited, i, j)res = max(result, count)print(result)
http://www.dtcms.com/a/331184.html

相关文章:

  • 图论(5)最小生成树算法
  • Claude Code 国内直接使用,原生支持 Windows 免WSL安装教程
  • Day56--图论--108. 冗余的边(卡码网),109. 冗余的边II(卡码网)
  • Day58--图论--117. 软件构建(卡码网),47. 参加科学大会(卡码网)
  • MySQL窗口函数与PyMySQL以及SQL注入
  • MySQLl中OFFSET 的使用方法
  • 中国AI生态加速迭代,AI硬件引领人机互动新范式
  • LeetCode 分类刷题:2302. 统计得分小于 K 的子数组数目
  • Gradle(四)Maven 项目迁移 Gradle 项目实践
  • 文件服务器:samba
  • Java 并发新范式:用 Structured Concurrency 优雅收拾多线程烂摊子
  • 编排之神-Kubernetes微服务专题--ingress-nginx及金丝雀Canary的演练
  • 电动自行车:中国式制霸
  • 支付域——账户系统设计
  • 2025年Java大厂面试场景题全解析:高频考点与实战攻略
  • 优德普SAP一体化平台有哪些功能?
  • 力扣(盛最多水的容器)
  • Java基础 8.14
  • 力扣-5.最长回文子串
  • MySQL的索引(索引的创建和设计原则):
  • 初识c语言————缓冲区字符滞留
  • 天马 TM150XDHG01-04 宽温高亮液晶模组技术档案
  • **标题:发散创新,探索编程中的平衡设计****摘要**:本文将探讨如何在编程中运用平衡设计思想,通过实例分析与
  • STM32F103 basic定时器的介绍和应用
  • 2021-2025全国监测国控断面地表水水质数据
  • P12348 [蓝桥杯 2025 省 A 第二场] 交互
  • 每日任务day0814:小小勇者成长记之钓鱼日记(字典推导式)
  • gpt2架构学习(1)
  • PDM 如何通过 ERP/PLM 释放数据价值?
  • 力扣面试150(56/150)