代码随想录算法训练营 Day 45

8 minute read

Published:

Q1. KamaCoder 101

孤岛是指不靠边的陆地,可以先将所有与边界靠近的陆地标记,然后再遍历所有岛屿,找到面积总和

深度优先搜索

directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]

def dfs(x, y, c=0):
    for dx, dy in directions:
        nx = x + dx
        ny = y + dy
        
        if nx < 0 or nx >= len(grid) or ny < 0 or ny >= len(grid[0]):
            continue
        
        if grid[nx][ny] == 1:
            grid[nx][ny] = 2
            c = dfs(nx, ny, c + 1)
            
    return c

if __name__ == '__main__':
    n, m  = map(int, input().split())
    
    grid = []
    for _ in range(n):
        grid.append(list(map(int, input().split())))
    
    for i in range(n):
        if grid[i][0] == 1:
            grid[i][0] = 2
            dfs(i, 0)
        
        if grid[i][m - 1] == 1:
            grid[i][m - 1] = 2
            dfs(i, m - 1)
    
    for j in range(m):
        if grid[0][j] == 1:
            grid[0][j] = 2
            dfs(0, j)
            
        if grid[n - 1][j] == 1:
            grid[n - 1][j] = 2
            dfs(n - 1, j)
    
    res = 0
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 1:
                grid[i][j] = 2
                res += dfs(i, j, 1)
    
    print(res)

广度优先搜索

只要加入队列就代表走过,就需要标记,而不是从队列拿出来的时候再去标记走过

from collections import deque

directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]

def bfs(x, y, area=0):
    queue = deque([])
    queue.append((x, y))
    
    while queue:
        curr_x, curr_y = queue.popleft()
        for dx, dy in directions:
            nx = curr_x + dx
            ny = curr_y + dy
            
            if nx < 0 or nx >= len(grid) or ny < 0 or ny >= len(grid[0]):
                continue
            
            if grid[nx][ny] == 1:
                grid[nx][ny] = 2
                area += 1
                queue.append((nx, ny))
    
    return area
    

if __name__ == '__main__':
    n, m  = map(int, input().split())
    
    grid = []
    for _ in range(n):
        grid.append(list(map(int, input().split())))
    
    for i in range(n):
        if grid[i][0] == 1:
            grid[i][0] = 2
            bfs(i, 0)
        
        if grid[i][m - 1] == 1:
            grid[i][m - 1] = 2
            bfs(i, m - 1)
    
    for j in range(m):
        if grid[0][j] == 1:
            grid[0][j] = 2
            bfs(0, j)
            
        if grid[n - 1][j] == 1:
            grid[n - 1][j] = 2
            bfs(n - 1, j)
    
    res = 0
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 1:
                grid[i][j] = 2
                res += bfs(i, j, 1)
    
    print(res)

Q2. KamaCoder 102

和Q1类似,只是现在需要将所有孤岛变成海,因此将靠近边界的所有陆地设置为2,并且在后面将其重新设置成1

深度优先遍历

directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]

def dfs(x, y):
    for dx, dy in directions:
        nx, ny = x + dx, y + dy
        
        if nx < 0 or nx >= len(grid) or ny < 0 or ny >= len(grid[0]):
            continue
        
        if grid[nx][ny] == 1:
            grid[nx][ny] = 2
            dfs(nx, ny)


if __name__ == '__main__':
    n, m = map(int, input().split())
    
    grid = []
    for _ in range(n):
        grid.append(list(map(int, input().split())))
    
    for i in range(n):
        if grid[i][0] == 1:
            grid[i][0] = 2
            dfs(i, 0)
            
        if grid[i][m - 1] == 1:
            grid[i][m - 1] = 2
            dfs(i, m - 1)
    
    for j in range(m):
        if grid[0][j] == 1:
            grid[0][j] = 2
            dfs(0, j)
        
        if grid[n - 1][j] == 1:
            grid[n - 1][j] = 2
            dfs(n - 1, j)
    
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 1:
                grid[i][j] = 0
            if grid[i][j] == 2:
                grid[i][j] = 1
    
    for line in grid:
        print(' '.join(map(str, line)))

广度优先搜索

from collections import deque

directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]

def bfs(x, y):
    queue = deque([])
    queue.append((x, y))
    
    while queue:
        cx, cy = queue.popleft()
        
        for dx, dy in directions:
            nx, ny = cx + dx, cy + dy
            
            if nx < 0 or nx >= len(grid) or ny < 0 or ny >= len(grid[0]):
                continue
            
            if grid[nx][ny] == 1:
                grid[nx][ny] = 2
                queue.append((nx, ny))


if __name__ == '__main__':
    n, m = map(int, input().split())
    
    grid = []
    for _ in range(n):
        grid.append(list(map(int, input().split())))
    
    for i in range(n):
        if grid[i][0] == 1:
            grid[i][0] = 2
            bfs(i, 0)
            
        if grid[i][m - 1] == 1:
            grid[i][m - 1] = 2
            bfs(i, m - 1)
    
    for j in range(m):
        if grid[0][j] == 1:
            grid[0][j] = 2
            bfs(0, j)
        
        if grid[n - 1][j] == 1:
            grid[n - 1][j] = 2
            bfs(n - 1, j)
    
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 1:
                grid[i][j] = 0
            if grid[i][j] == 2:
                grid[i][j] = 1
    
    for line in grid:
        print(' '.join(map(str, line)))

Q3. KamaCoder 103

逆向思维:要找到能够同时流向第一边界和第二边界的格子,也就是说从第一边界和第二边界出发都能到达这个格子

深度优先搜索

directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]

def dfs(x, y, flag):
    for dx, dy in directions:
        nx, ny = x + dx, y + dy
    
        if 0 <= nx < len(grid) and 0 <= ny < len(grid[0]) and grid[nx][ny] >= grid[x][y]:
            if flag == 1 and (nx, ny) not in visited1:
                visited1.add((nx, ny))
                dfs(nx, ny, flag)
            elif flag == 2 and (nx, ny) not in visited2:
                visited2.add((nx, ny))
                dfs(nx, ny, flag)
    

if __name__ == '__main__':
    n, m = map(int, input().split())
    
    grid = []
    for _ in range(n):
        grid.append(list(map(int, input().split())))
    
    visited1 = set()
    for i in range(n):
        visited1.add((i, 0))
        dfs(i, 0, 1)
    
    for j in range(m):
        visited1.add((0, j))
        dfs(0, j, 1)
    
    visited2 = set()
    for i in range(n):
        visited2.add((i, m - 1))
        dfs(i, m - 1, 2)
    
    for j in range(m):
        visited2.add((n - 1, j))
        dfs(n - 1, j, 2)
    
    res = visited1 & visited2
    
    for x, y in res:
        print(x, y)

广度优先搜索

from collections import deque

directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]

def bfs(x, y, flag):
    queue = deque([])
    queue.append((x, y))
    
    while queue:
        cx, cy = queue.popleft()
        
        for dx, dy in directions:
            nx, ny = cx + dx, cy + dy
        
            if 0 <= nx < len(grid) and 0 <= ny < len(grid[0]) and grid[nx][ny] >= grid[cx][cy]:
                if flag == 1 and (nx, ny) not in visited1:
                    visited1.add((nx, ny))
                    queue.append((nx, ny))
                elif flag == 2 and (nx, ny) not in visited2:
                    visited2.add((nx, ny))
                    queue.append((nx, ny))
    

if __name__ == '__main__':
    n, m = map(int, input().split())
    
    grid = []
    for _ in range(n):
        grid.append(list(map(int, input().split())))
    
    visited1 = set()
    for i in range(n):
        visited1.add((i, 0))
        bfs(i, 0, 1)
    
    for j in range(m):
        visited1.add((0, j))
        bfs(0, j, 1)
    
    visited2 = set()
    for i in range(n):
        visited2.add((i, m - 1))
        bfs(i, m - 1, 2)
    
    for j in range(m):
        visited2.add((n - 1, j))
        bfs(n - 1, j, 2)
    
    res = visited1 & visited2
    
    for x, y in res:
        print(x, y)

Q4. KamaCoder 104

运行两次搜索,第一次将岛屿进行标记,并且存储每块岛屿的面积;第二次找到海的位置,并且判断将其变为陆地后最大的岛屿面积

注意点

  1. 第二次遍历只需要看不同方向的四个格子即可,并且对于同一块岛屿,只能统计一次
  2. 有整块全是陆地,不存在海的特殊情况

深度优先搜索

directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]

def dfs(x, y, tag, area):
    for dx, dy in directions:
        nx, ny = x + dx, y + dy
        
        if 0 <= nx < len(grid) and 0 <= ny < len(grid[0]) and grid[nx][ny] == 1:
            grid[nx][ny] = tag
            area = dfs(nx, ny, tag, area + 1)
    
    return area

if __name__ == '__main__':
    n, m = map(int, input().split())
    
    grid = []
    for _ in range(n):
        grid.append(list(map(int, input().split())))
    
    area_with_tag = {0:0}
    t = 2
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 1:
                grid[i][j] = t
                a = dfs(i, j, t, 1)
                area_with_tag[t] = a
                t += 1
    
    res = 0
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 0:
                max_merged_area = 1
                vis = set()
                for dx, dy in directions:
                    surrounding_x, surrounding_y = i + dx, j + dy
                    
                    if 0 <= surrounding_x < len(grid) and 0 <= surrounding_y < len(grid[0]) and grid[surrounding_x][surrounding_y] not in vis:
                        max_merged_area += area_with_tag[grid[surrounding_x][surrounding_y]]
                        vis.add(grid[surrounding_x][surrounding_y])
                
                res = max(res, max_merged_area)
    
    if res == 0:
        print(n * m)
    else:
        print(res)

广度优先搜索

from collections import deque

directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]

def bfs(x, y, tag, area):
    queue = deque([(x, y)])
    
    while queue:
        cx, cy = queue.popleft()
        
        for dx, dy in directions:
            nx, ny = cx + dx, cy + dy
            
            if 0 <= nx < len(grid) and 0 <= ny < len(grid[0]) and grid[nx][ny] == 1:
                grid[nx][ny] = tag
                area += 1
                queue.append((nx, ny))
    
    return area

if __name__ == '__main__':
    n, m = map(int, input().split())
    
    grid = []
    for _ in range(n):
        grid.append(list(map(int, input().split())))
    
    area_with_tag = {0:0}
    t = 2
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 1:
                grid[i][j] = t
                a = bfs(i, j, t, 1)
                area_with_tag[t] = a
                t += 1
    
    res = 0
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 0:
                max_merged_area = 1
                vis = set()
                for dx, dy in directions:
                    surrounding_x, surrounding_y = i + dx, j + dy
                    
                    if 0 <= surrounding_x < len(grid) and 0 <= surrounding_y < len(grid[0]) and grid[surrounding_x][surrounding_y] not in vis:
                        max_merged_area += area_with_tag[grid[surrounding_x][surrounding_y]]
                        vis.add(grid[surrounding_x][surrounding_y])
                
                res = max(res, max_merged_area)
    
    if res == 0:
        print(n * m)
    else:
        print(res)