代码随想录D52-53 图论 Python

news/2025/2/23 16:45:41

目录

101. 孤岛的总面积 

102. 沉没孤岛

103. 水流问题

104. 建造最大岛屿


101. 孤岛的总面积 

要点:

整体来说是一个图着色的问题。

这道题目的思路符合直觉,但代码实现会和直觉有差别。如果仅使用visit记录不使用着色,会遇到非常多的判断问题。

最好的解决方案是对边缘进行判断,然后先将所有挨着岸边的岛屿着色成海洋,随后重新初始化面积计数,对中央的孤岛面积进行计算。

实现1 深度优先遍历:
python">
direct = [[1, 0], [0, 1], [-1, 0], [0, -1]]


def dfs(grid, x, y):
    
    global count
    ## 凡遇到节点即着色
    count += 1 
    grid[x][y] = 0
        
    for i, j in direct:
        n_x, n_y = x + i, y + j 
        if 0 <= n_x < len(grid) and 0 <= n_y < len(grid[0]) and grid[n_x][n_y] == 1:
            dfs(grid, n_x, n_y)

def main():
    
    global count
    
    n, m = map(int, input().split())
    grid = [list(map(int, input().split())) for _ in range(n)]
    
    count = 0
    
    ## 清除左右边界
    for i in range(n):
        ## 清除上下边界
        for j in range(m):
            if i == 0 or j == 0 or i == n-1 or j == m-1:
                if grid[i][j]:
                    dfs(grid, i, j)
    ## 正式的遍历
    count = 0
    for i in range(n):
        for j in range(m):
            if grid[i][j]:
                dfs(grid, i, j)
    
    print(count)

if __name__ == '__main__':
    
    main()
实现2 广度优先遍历:
python">from collections import deque


direct = [[1, 0], [0, 1], [-1, 0], [0, -1]]

def bfs(grid, x, y, ):
    
    count = 1
    que = deque([])
    que.append([x, y])
    
    while que:
        
        cur_x, cur_y = que.popleft()
        grid[cur_x][cur_y] = 0
        
        for i, j in direct:
            
            next_x, next_y = cur_x + i, cur_y + j 
            if next_x < 0 or next_y < 0 or next_x >= len(grid) or next_y >= len(grid[0]):
                continue
            
            if grid[next_x][next_y] == 1:
                count += 1
                grid[next_x][next_y] = 0
                que.append([next_x, next_y])
    
    return count

def main():
    
    n, m = map(int, input().split())
    grid = [list(map(int, input().split())) for _ in range(n)]
    
    count = 0
    
    for i in range(n):
        for j in range(m):
            if i == 0 or j == 0 or i == n-1 or j == m-1:
                if grid[i][j] == 1:
                    bfs(grid, i, j, )
    
    # print(grid)
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 1:
                cur_count = bfs(grid, i, j, )
                count += cur_count
                
    print(count)


if __name__ == '__main__':
    
    main()

102. 沉没孤岛

要点:

同样是图着色问题,但是要着色的区域和上一题刚好相反。

由于要输出变化后的矩阵,那么就按照之前的方法先将边缘位置全部变为2,最后做一次转换即可。

实现1 广度优先搜索:

使用一个自定义标记,很快就能够完成了

python">
from collections import deque

direct = [[1, 0], [0, 1], [-1, 0], [0, -1]]

def bfs(grid, x, y, l = 2):
    
    count = 1
    que = deque([])
    que.append([x, y])
    grid[x][y] = l
    
    while que:
        cur_x, cur_y = que.popleft()
        
        for i, j in direct:
            next_x, next_y = cur_x + i, cur_y + j 
            
            if next_x < 0 or next_y < 0 or next_x >= len(grid) or next_y >= len(grid[0]):
                continue
            
            if grid[next_x][next_y] == 1:
                grid[next_x][next_y] = l
                que.append([next_x, next_y])
                count += 1
    
    return count
    
def main():
    
    count = 0
    
    n, m = map(int, input().split())
    grid = [list(map(int, input().split())) for i in range(n)]
    
    for i in range(n):
        for j in range(m):
            if i == 0 or j == 0 or i == n-1 or j == m-1:
                if grid[i][j] == 1:
                    bfs(grid, i, j)
    
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 1:
                count += bfs(grid, i, j, l = 0)
    
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 2:
                grid[i][j] = 1
        
        print(' '.join(map(str, grid[i])))
    
if __name__ == '__main__':
    
    main()
    
    
实现2 深度优先遍历:

本题主要就是在做着色,不需要计数。

python">direct = [[1, 0], [0, 1], [-1, 0], [0, -1]]

def dfs(grid, x, y, l = 0):
    
    grid[x][y] = l
    
    for i, j in direct:
        next_x, next_y = x + i, y + j 
        
        if next_x < 0 or next_y < 0 or next_x >= len(grid) or next_y >= len(grid[0]):
            continue 
        
        if grid[next_x][next_y] == 0 or grid[next_x][next_y] == 2:
            continue
        
        dfs(grid, next_x, next_y, l)
    

def main():
    
    n, m = map(int, input().split())
    grid = [list(map(int, input().split())) for i in range(n)]
    
    
    for i in range(n):
        for j in range(m):
            if i == 0 or j == 0 or i == n-1 or j == m-1:
                if grid[i][j] == 1:
                    dfs(grid, i, j, 2)
                    
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 1:
                dfs(grid, i, j)
    
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 2:
                grid[i][j] = 1
        
        print(' '.join(map(str, grid[i])))

103. 水流问题

要点:

如果是用暴力解法,就是从每个节点进行搜索,最后记录并输出结果。

如果逆向思考,使用着色的思想,从两个边界出发,对整张图进行着色,附上不同的颜色,最终输出这些位置。就可以实现只遍历一次边框位置。

实现:
python">first = set()
second = set()
directions = [[-1, 0], [0, 1], [1, 0], [0, -1]]

def dfs(i, j, graph, visited, side):
    if visited[i][j]:
        return
    
    visited[i][j] = True
    side.add((i, j))
    
    for x, y in directions:
        new_x = i + x
        new_y = j + y
        if (
            0 <= new_x < len(graph)
            and 0 <= new_y < len(graph[0])
            and int(graph[new_x][new_y]) >= int(graph[i][j])
        ):
            dfs(new_x, new_y, graph, visited, side)

def main():
    global first
    global second
    
    N, M = map(int, input().strip().split())
    graph = []
    for _ in range(N):
        row = input().strip().split()
        graph.append(row)
    
    # 是否可到达第一边界
    visited = [[False] * M for _ in range(N)]
    for i in range(M):
        dfs(0, i, graph, visited, first)
    for i in range(N):
        dfs(i, 0, graph, visited, first)
    
    # 是否可到达第二边界
    visited = [[False] * M for _ in range(N)]
    for i in range(M):
        dfs(N - 1, i, graph, visited, second)
    for i in range(N):
        dfs(i, M - 1, graph, visited, second)

    # 可到达第一边界和第二边界
    res = first & second
    
    for x, y in res:
        print(f"{x} {y}")
    
    
if __name__ == "__main__":
    main()

104. 建造最大岛屿

 要点:

读完题目发现难点是确定应该将陆地建造在哪里。如果每个位置都做一次搜索,时间肯定会慢。

这里可以使用字典的方式,使用defaultdict记录一下每个岛的id,坐标,面积。然后再对每个位置上建造陆地能带来的最大面积做计算即可。

具体来说,建立defaultdict来记录每个岛屿id的面积,每个grid着色成岛屿id。最终统计每个节点周围岛屿id对应的面积之和

实现:
python">
from collections import defaultdict

direct = [[1, 0], [0, 1], [-1, 0], [0, -1]]

def count_ones(grid):
    return sum(row.count(1) for row in grid)
    

def dfs(grid, visit, x, y, idx):
    
    global area
    
    if visit[x][y]:
        return
    
    visit[x][y] = True
    grid[x][y] = idx
    area += 1
    
    for i, j in direct:
        next_x, next_y = x + i, y + j 
        if 0 <= next_x < len(grid) and 0 <= next_y < len(grid[0]) and grid[next_x][next_y] == 1:
            dfs(grid, visit, next_x, next_y, idx)

def main():
    
    global area
    
    n, m = map(int, input().split())
    grid = [list(map(int, input().split())) for _ in range(n)]
    
    if count_ones(grid) == n * m:
        print(count_ones(grid))
        return
    
    visit = [[False] * m for _ in range(n)]
    island_area = defaultdict()
    
    idx = 2
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 1 and not visit[i][j]:
                area = 0
                dfs(grid, visit, i, j, idx)
                island_area[idx] = area
                idx += 1 
    
    max_area = 1
    
    for i in range(n):
        for j in range(m):
            new_island = grid[i][j]
            merge_area = 1
            idx_set = set()
            for x, y in direct:
                if 0 <= i + x < len(grid) and 0 <= j + y < len(grid[0]):
                    idx = grid[i + x][j + y]
                    if idx not in idx_set:
                        merge_area += island_area.get(idx, 0)
                        idx_set.add(idx)
            
            if merge_area > max_area:
                max_area = merge_area
    
    print(max_area)
    
if __name__ == '__main__':
    main()


http://www.niftyadmin.cn/n/5863592.html

相关文章

免填邀请码工具:赋能六大核心场景,重构App增长新模型

在移动互联网流量红利逐渐消退的当下&#xff0c;用户转化漏斗中的每个环节都直接影响着App的商业价值。openinstall的免填邀请码工具&#xff0c;通过深度整合渠道归因与轻量化SDK方案&#xff0c;在用户首次打开App时即完成关键信息匹配&#xff0c;重构了传统用户增长模型。…

利用Postman和Apipost进行WebSocket调试和文档设计

在现代 Web 开发中&#xff0c;Websocket 作为一种常见的 Web 协议&#xff0c;与 Restful API 有着本质的不同。Restful API是基于请求-响应模式的单向通信&#xff0c;而 WebSocket 提供全双工通信渠道&#xff0c;允许客户端和服务器之间进行实时双向数据传输。这种特性使得…

MapReduce理论知识与实践

1. 什么是MapReduce MapReduce是一种分布式计算模型&#xff0c;用于处理大量数据。它由Google提出&#xff0c;广泛应用于大数据处理平台&#xff08;如Hadoop&#xff09;。MapReduce模型的核心思想是将任务分解成两个阶段&#xff1a;Map阶段和Reduce阶段。 Map阶段&#x…

JavaSE学习笔记25-反射(reflection)

反射 在Java中&#xff0c;反射&#xff08;Reflection&#xff09; 是一种强大的机制&#xff0c;允许程序在运行时检查和操作类、方法、字段等信息。通过反射&#xff0c;可以动态地创建对象、调用方法、访问字段&#xff0c;甚至修改私有成员。反射的核心类是 java.lang.re…

Flutter开发的应用页面非常多时如何高效管理路由

文章目录 1. 集中式路由管理示例&#xff1a; 2. 动态路由生成 (onGenerateRoute)示例&#xff1a; 3. 模块化路由管理示例&#xff1a; 4. 使用路由管理库使用go_router的示例&#xff1a; 5. 路由分层管理总结 当Flutter应用中有大量页面时&#xff0c;路由管理变得复杂。为了…

第二届粤港澳大湾区数字经济与人工智能国际学术会议(DEAI 2025)

重要信息 2025年3月28-30日 I 广东省东莞市(广东科技学院-松山湖校区&#xff09; I www.icdeai.com 简介 第二届粤港澳大湾区数字经济与人工智能(DEAI 2025)将在2025年3月28-30日在广东省东莞市隆重举行。来自国内外高等院校、科学研究所、企事业单位的专家、教授、学者、…

Python 高级特性-切片

目录 切片 练习 小结 掌握了Python的数据类型、语句和函数&#xff0c;基本上就可以编写出很多有用的程序了。 比如构造一个1, 3, 5, 7, ..., 99的列表&#xff0c;可以通过循环实现&#xff1a; L [] n 1 while n < 99:L.append(n)n n 2 取list的前一半的元素&am…

常用高压缩率的视频容器格式,并进行大比例压缩

常用的高压缩率视频容器格式,包括*.mp4 、*.mkv、*.webM等。     容器格式本身并不直接决定压缩率,而是取决于容器中所使用的视频编码格式等因素。不过,在常见的视频容器格式中,一些容器在搭配特定编码格式时,通常能表现出较高的压缩效率,以下是相关介绍: 1 MKV格式 …