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

岛屿问题——DFS、BFS

重刷了一遍之前在代码随想录中的每日打卡时的岛屿问题,发现之前写的好多💩山代码,感兴趣的可以看看D56、D57、D58这几篇,不过可以看出写dfs与bfs确实是有进步与理解加深了,一大幸事。

有什么建议或者错误欢迎随时提出。

也欢迎你们学习下面的七道岛屿问题,若有问题或者需要交流,随时可评论区或私信。


岛屿数量

题目描述

​ 给定一个由 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
提示信息

img

​ 根据测试案例中所展示,岛屿数量共有 3 个,所以输出 3。

数据范围:

​ 1 <= N, M <= 50


深搜版

n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
# 记录访问过的陆地
visited=[[False for _ in range(m)] for _ in range(n)]
directions=[[-1,0],[0,-1],[0,1],[1,0]]  # dfs中上下左右四个方向
def dfs(i,j):
    # 递归终止条件
    if grid[i][j]=='0' or visited[i][j]==True:
        return

    visited[i][j]=True  #设置为已访问
    # 遍历四个方向
    for dire in directions:
        next_x,next_y=dire[0]+i,dire[1]+j   # 下一个方向的下标
        if 0<=next_x<n and 0<=next_y<m:
            dfs(next_x,next_y)

ans=0
for i in range(n):
    for j in range(m):
        if grid[i][j]=='1' and visited[i][j]==False:
            ans+=1
            dfs(i,j)
print(ans)

广搜版

n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
# 记录访问过的陆地
visited=[[False for _ in range(m)] for _ in range(n)]
directions=[[-1,0],[0,-1],[0,1],[1,0]]  # bfs中上下左右四个方向

from collections import deque

def bfs(i,j):
    visited[i][j]=True
    while que:
        x,y=que.popleft()
        for dire in directions:
            next_x,next_y=x+dire[0],y+dire[1]
            if 0<=next_x<n and 0<=next_y<m and grid[next_x][next_y]=='1' and visited[next_x][next_y]==False:
                que.append([next_x,next_y])
                # 加入队列就标记走过
                visited[next_x][next_y]=True
                 
ans=0
for i in range(n):
    for j in range(m):
        if grid[i][j]=='1' and visited[i][j]==False:
            que=deque([[i,j]])
            bfs(i,j)
            ans+=1
print(ans)


岛屿的最大面积

题目描述

​ 给定一个由 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
提示信息

img

​ 样例输入中,岛屿的最大面积为 4。

​ 数据范围:

​ 1 <= M, N <= 50。


深搜版

n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
# 记录访问过的陆地
visited=[[False for _ in range(m)] for _ in range(n)]
directions=[[-1,0],[0,-1],[0,1],[1,0]] 
def dfs(i,j):
    global area
    # 只要遇到水或者访问过的陆地就终止
    if grid[i][j]=='0' or visited[i][j]==True:
        return
    visited[i][j]=True
    area+=1
    for dire in directions:
        next_x,next_y=i+dire[0],j+dire[1]
        if 0<=next_x<n and 0<=next_y<m:
            dfs(next_x,next_y)

ans=0
for i in range(n):
    for j in range(m):
        if grid[i][j]=='1' and visited[i][j]==False:
            area=0
            dfs(i,j)
            ans=max(ans,area)
print(ans)

广搜版

n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
# 记录访问过的陆地
visited=[[False for _ in range(m)] for _ in range(n)]
directions=[[-1,0],[0,-1],[0,1],[1,0]]  

from collections import deque
def bfs(i,j):
    global area
    visited[i][j]=True
    while que:
        x,y=que.popleft()
        area+=1
        for dire in directions:
            next_x,next_y=x+dire[0],y+dire[1]
            if 0<=next_x<n and 0<=next_y<m and grid[next_x][next_y]=='1'and visited[next_x][next_y]==False:
                que.append([next_x,next_y])
                visited[next_x][next_y]=True
                
ans=0
for i in range(n):
    for j in range(m):
        if grid[i][j]=='1' and visited[i][j]==False:
            area=0
            que=deque([[i,j]])
            bfs(i,j)
            ans=max(ans,area)
print(ans)


孤岛的总面积

题目描述

​ 给定一个由 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
输出示例
1
提示信息

img


​ 在矩阵中心部分的岛屿,因为没有任何一个单元格接触到矩阵边缘,所以该岛屿属于孤岛,总面积为 1。

​ 数据范围:

​ 1 <= M, N <= 50。


深搜版

n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
# 记录访问过的陆地
visited=[[False for _ in range(m)] for _ in range(n)]
directions=[[-1,0],[0,-1],[0,1],[1,0]]  

def dfs(i,j):
    global flag,area
    if visited[i][j]==True or grid[i][j]=='0':
        return
    area+=1
    visited[i][j]=True
    for dire in directions:
        next_x,next_y=i+dire[0],j+dire[1]
        if next_x<0 or next_y<0 or next_x>=n or next_y>=m:
            flag=False
            continue
        dfs(next_x,next_y)

ans=0
for i in range(n):
    for j in range(m):
        if grid[i][j]=='1' and visited[i][j]==False:
            area=0
            flag=True  # 标记是不是孤岛
            dfs(i,j)
            if flag:
                ans+=area
print(ans)

广搜版

n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
# 记录访问过的陆地
visited=[[False for _ in range(m)] for _ in range(n)]
directions=[[-1,0],[0,-1],[0,1],[1,0]]  

from collections import deque
def bfs(i,j):
    global flag,area
    visited[i][j]=True
    while que:
        x,y=que.popleft()
        area+=1
        for dire in directions:
            next_x,next_y=x+dire[0],y+dire[1]
            if next_x<0 or next_y<0 or next_x>=n or next_y>=m:
                flag=False
                continue
            if grid[next_x][next_y]=='1' and visited[next_x][next_y]==False:
                que.append([next_x,next_y])
                visited[next_x][next_y]=True

ans=0
for i in range(n):
    for j in range(m):
        if grid[i][j]=='1' and visited[i][j]==False:
            area=0
            flag=True  # 标记是不是孤岛
            que=deque([[i,j]])
            bfs(i,j)
            if flag:
                ans+=area
print(ans)


沉没孤岛

题目描述

​ 给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,且完全被水域单元格包围。孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。

​ 现在你需要将所有孤岛“沉没”,即将孤岛中的所有陆地单元格(1)转变为水域单元格(0)。

输入描述

​ 第一行包含两个整数 N, M,表示矩阵的行数和列数。

​ 之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。

输出描述

​ 输出将孤岛“沉没”之后的岛屿矩阵。 注意:每个元素后面都有一个空格

输入示例
4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1
输出示例
1 1 0 0 0
1 1 0 0 0
0 0 0 0 0
0 0 0 1 1
提示信息

img

​ 将孤岛沉没。


img

​ 数据范围:

​ 1 <= M, N <= 50。


深搜版

# 将边缘的陆地标记为2,再重新遍历一遍岛屿.为1的就是孤岛,改成0,再把2改为1
n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
visited=[[False for _ in range(m)] for _ in range(n)]
directions=[[-1,0],[0,-1],[0,1],[1,0]]  

# 将边缘的岛屿标记为2
def dfs(i,j):
    if visited[i][j]==True or grid[i][j]!='1':
        return

    visited[i][j]=True
    grid[i][j]='2'
    for dire in directions:
        next_x,next_y=i+dire[0],j+dire[1]
        if 0<=next_x<n and 0<=next_y<m:
            dfs(next_x,next_y)

# 标记左边缘和右边缘的岛屿
for i in range(n):
    dfs(i,0)
    dfs(i,m-1)
# 标记上边缘和下边缘的岛屿
for j in range(m):
    dfs(0,j)
    dfs(n-1,j)

# 将标记为2的岛屿改为1,标记为1的岛屿改为0
for i in range(n):
    for j in range(m):
        if grid[i][j]=='2':
            grid[i][j]='1'
        elif grid[i][j]=='1':
            grid[i][j]='0'

# 打印
for i in grid:
    print(' '.join(i))


广搜版

# 将边缘的陆地标记为2,再重新遍历一遍岛屿.为1的就是孤岛,改成0,再把2改为1
from collections import deque
n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
visited=[[False for _ in range(m)] for _ in range(n)]
directions=[[-1,0],[0,-1],[0,1],[1,0]]  

# 将边缘的岛屿标记为2
def bfs(i,j):
    que=deque([[i,j]])
    visited[i][j]=True
    grid[i][j]='2'
    while que:
        x,y=que.popleft()
        for dire in directions:
            next_x,next_y=x+dire[0],y+dire[1]
            if 0<=next_x<n and 0<=next_y<m and grid[next_x][next_y]=='1' and visited[next_x][next_y]==False:
                que.append([next_x,next_y])
                visited[next_x][next_y]=True
                grid[next_x][next_y]='2'

# 标记左边缘和右边缘的岛屿
for i in range(n):
    if grid[i][0]=='1' and visited[i][0]==False:
        bfs(i,0)
    if grid[i][m-1]=='1' and visited[i][m-1]==False:
        bfs(i,m-1)
# 标记上边缘和下边缘的岛屿
for j in range(m):
    if grid[0][j]=='1' and visited[0][j]==False:
        bfs(0,j)
    if grid[n-1][j]=='1' and visited[n-1][j]==False:
        bfs(n-1,j)

# 将标记为2的岛屿改为1,标记为1的岛屿改为0
for i in range(n):
    for j in range(m):
        if grid[i][j]=='2':
            grid[i][j]='1'
        elif grid[i][j]=='1':
            grid[i][j]='0'

# 打印
for i in grid:
    print(' '.join(i))


水流问题

题目描述

​ 现有一个 N × M 的矩阵,每个单元格包含一个数值,这个数值代表该位置的相对高度。矩阵的左边界和上边界被认为是第一组边界,而矩阵的右边界和下边界被视为第二组边界。

​ 矩阵模拟了一个地形,当雨水落在上面时,水会根据地形的倾斜向低处流动,但只能从较高或等高的地点流向较低或等高并且相邻(上下左右方向)的地点。我们的目标是确定那些单元格,从这些单元格出发的水可以达到第一组边界和第二组边界。

输入描述

​ 第一行包含两个整数 N 和 M,分别表示矩阵的行数和列数。

​ 后续 N 行,每行包含 M 个整数,表示矩阵中的每个单元格的高度。

输出描述

​ 输出共有多行,每行输出两个整数,用一个空格隔开,表示可达第一组边界和第二组边界的单元格的坐标,输出顺序任意。

输入示例
5 5
1 3 1 2 4
1 2 1 3 2
2 4 7 2 1
4 5 6 1 1
1 4 1 2 1
输出示例
0 4
1 3
2 2
3 0
3 1
3 2
4 0
4 1
提示信息

img

​ 图中的蓝色方块上的雨水既能流向第一组边界,也能流向第二组边界。所以最终答案为所有蓝色方块的坐标。

数据范围:

​ 1 <= M, N <= 100。


深搜版

n,m=map(int,input().split())
grid=[list(map(int,input().split())) for _ in range(n)]
directions=[[-1,0],[0,1],[1,0],[0,-1]]
def dfs(i,j):
    global flag1,flag2
    # 剪枝,相当于如果遍历到的节点如果在答案中,说明一定可以流向两组边界
    if [i,j] in ans:
        flag1,flag2=True,True
        return
    # 访问过,返回
    if visited[i][j]:
        return

    visited[i][j]=True

    # 这两个节点是两组边界的交叉点
    if i==0 and j==m-1 or i==n-1 and j==0:
        flag1,flag2=True,True
        return

    
    if i==0 or j==0:
        flag1=True
    if i==n-1 or j==m-1:
        flag2=True

    for dx,dy in directions:
        next_x,next_y=i+dx,j+dy
        if 0<=next_x<n and 0<=next_y<m and grid[next_x][next_y]<=grid[i][j]:
            dfs(next_x,next_y)
            
ans=[]
for i in range(n):
    for j in range(m):
        visited=[[False]*m for _ in range(n)]
        flag1,flag2=False,False     # 能不能留到两组边界
        dfs(i,j)
        if flag1 and flag2:
            ans.append([i,j])

for i,j in ans:
    print(i,j)

广搜版

n,m=map(int,input().split())
grid=[list(map(int,input().split())) for _ in range(n)]
directions=[[-1,0],[0,1],[1,0],[0,-1]]
from collections import deque
def bfs(i,j):
    global flag1,flag2
    visited[i][j]=True
    que=deque([[i,j]])
    while que:
        x,y=que.popleft()
        if [x,y] in ans:
            flag1,flag2=True,True
            break

        if x==0 or y==0:
            flag1=True
        if x==n-1 or y==m-1:
            flag2=True
        for a,b in directions:
            next_x,next_y=a+x,b+y
            if 0<=next_x<n and 0<=next_y<m and visited[next_x][next_y]==False and grid[next_x][next_y]<=grid[x][y]:  
                que.append([next_x,next_y])
                visited[next_x][next_y]=True

ans=[]
for i in range(n):
    for j in range(m):
        visited=[[False]*m for _ in range(n)]
        flag1,flag2=False,False     # 能不能流到两组边界
        bfs(i,j)
        if flag1 and flag2:
            ans.append([i,j])

for i,j in ans:
    print(i,j)


建造最大岛屿

题目描述

​ 给定一个由 1(陆地)和 0(水)组成的矩阵,你最多可以将矩阵中的一格水变为一块陆地,在执行了此操作之后,矩阵中最大的岛屿面积是多少。

​ 岛屿面积的计算方式为组成岛屿的陆地的总数。岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设矩阵外均被水包围。

输入描述

​ 第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。

输出描述

​ 输出一个整数,表示最大的岛屿面积。

输入示例
4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1
输出示例
6
提示信息

img

​ 对于上面的案例,有两个位置可将 0 变成 1,使得岛屿的面积最大,即 6。

img

​ 数据范围:

​ 1 <= M, N <= 50。


深搜版

# 每次将每一块水域标记成陆地,再计算以这块陆地延申的最大面积
n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
directions=[[-1,0],[1,0],[0,1],[0,-1]]
def dfs(i,j):
    global area
    if visited[i][j]==True or grid[i][j]=='0':
        return
    
    visited[i][j]=True
    area+=1

    for x,y in directions:
        nx,ny=i+x,j+y
        if 0<=nx<n and 0<=ny<m:
            dfs(nx,ny)

ans=0
# 标记有没有水域,如果没有,则进不入循环,最大面积会被计算为零,所以需要标记如果没有进入循环,则最大面积则是n*m
flag=False  
for i in range(n):
    for j in range(m):
        area=0
        visited=[[False]*m for _ in range(n)] 
        
        if grid[i][j]=='0':
            flag=True
            grid[i][j]='1'  # 改为陆地
            dfs(i,j)
            ans=max(area,ans)
            grid[i][j]='0'  # 计算完还原回来
# 如果这个地图没有一块水域
if flag==False:
    ans=n*m
        
print(ans)

广搜版

from collections import deque
n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
directions=[[-1,0],[1,0],[0,1],[0,-1]]
def bfs(i,j):
    global area
    que=deque([[i,j]])
    visited[i][j]=True
    while que:
        cx,cy=que.popleft()
        area+=1
        for x,y in directions:
            nx,ny=cx+x,cy+y
            if 0<=nx<n and 0<=ny<m and visited[nx][ny]==False and grid[nx][ny]=='1':
                que.append([nx,ny])
                visited[nx][ny]=True

ans=0
flag=False  
for i in range(n):
    for j in range(m):
        area=0
        visited=[[False]*m for _ in range(n)] 
        
        if grid[i][j]=='0':
            flag=True
            grid[i][j]='1'  
            bfs(i,j)
            ans=max(area,ans)
            grid[i][j]='0'  
if flag==False:
    ans=n*m
        
print(ans)


岛屿的周长

题目描述

​ 给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。

​ 你可以假设矩阵外均被水包围。在矩阵中恰好拥有一个岛屿,假设组成岛屿的陆地边长都为 1,请计算岛屿的周长。岛屿内部没有水域。

输入描述

​ 第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。

输出描述

输出一个整数,表示岛屿的周长。

输入示例
5 5
0 0 0 0 0 
0 1 0 1 0
0 1 1 1 0
0 1 1 1 0
0 0 0 0 0
输出示例
14
提示信息

img

​ 岛屿的周长为 14。

​ 数据范围:

​ 1 <= M, N <= 50。


深搜版

n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
directions=[[-1,0],[1,0],[0,1],[0,-1]]
visited=[[False]*m for _ in range(n)]
def dfs(i,j):
    global ans
    # 边界外或者遇到水了周长就加一
    if i<0 or j<0 or i>=n or j>=m or grid[i][j]=='0':
        ans+=1
        return
        
    if grid[i][j]=='0' or visited[i][j]==True:
        return

    visited[i][j]=True
    for x,y in directions:
        nx,ny=i+x,j+y
        dfs(nx,ny)

ans=0
for i in range(n):
    for j in range(m):
        if grid[i][j]=='1' and visited[i][j]==False:
            dfs(i,j)     
print(ans)

广搜版

from collections import deque
n,m=map(int,input().split())
grid=[input().split() for _ in range(n)]
directions=[[-1,0],[1,0],[0,1],[0,-1]]
visited=[[False]*m for _ in range(n)]
def bfs(i,j):
    global ans
    que=deque([[i,j]])
    visited[i][j]=True
    while que:
        cx,cy=que.popleft()
        for x,y in directions:
            nx,ny=cx+x,cy+y
            if nx<0 or ny<0 or nx>=n or ny>=m or grid[nx][ny]=='0':
                ans+=1
                continue
            elif visited[nx][ny]==False:
                que.append([nx,ny])
                visited[nx][ny]=True

ans=0
for i in range(n):
    for j in range(m):
        if grid[i][j]=='1' and visited[i][j]==False:
            bfs(i,j)     
print(ans)

相关文章:

  • 高并发秒杀系统设计:关键技术解析与典型陷阱规避
  • 【Linux】Rhcsa复习 2
  • 基于51单片机语音实时采集系统
  • 仙剑奇侠传98柔情版游戏秘籍
  • 工业级安卓一体机在智能自助终端中的应用
  • Spark运行架构 RDD相关概念Spark-Core编程
  • 基于李永乐线性代数基础的行列式的起源于理解
  • Hqst的超薄千兆变压器HM82409S在Unitree宇树Go2智能机器狗的应用
  • 初步认识java
  • 关于香橙派OrangePi 5 Ultra 这个开源板子,开发Android
  • 通信算法之261: 时频分析- findpeaks 函数查找满足宽度要求的峰值
  • PyQt6基础_pyqtgraph_k线图缩放
  • 41、web前端开发之Vue3保姆教程(五 项目实战)
  • 足球比分分析页面可视化展示
  • ImportError: The ‘read_file‘ function requires the ‘pyogrio‘ or ‘fiona‘ package
  • 【深度学习与实战】3.1 逻辑回归模型
  • 网络相关基本概念
  • Rasa总体目录架构介绍
  • Python中如何用正则表达式精准匹配IP地址?
  • 常用环境部署(二十六)——Centos搭建MQTT服务端EMQX
  • 网站开发建设合同/百度竞价怎么排名第一
  • php租车网站源码/百度热搜广告位
  • 西安疫情最新数据消息今天/杭州seo联盟
  • 做网站维护前景/现在做推广的新渠道有哪些
  • 怎么样做网站 用网站赚钱/广告联盟论坛
  • web 开发 网站开发/写一篇软文1000字