一、島嶼數量(Kamacoder 99)
深度優先搜索:
# 定義四個方向:右、下、左、上,用于 DFS 中四向遍歷
direction = [[0, 1], [1, 0], [0, -1], [-1, 0]]def dfs(grid, visited, x, y):"""對一塊陸地進行深度優先遍歷并標記相鄰陸地:param grid: 二維網格:param visited: 是否訪問過的標記表:param x: 當前所在的行坐標:param y: 當前所在的列坐標"""for dx, dy in direction:next_x = x + dxnext_y = y + dy# 判斷是否越界if next_x < 0 or next_x >= len(grid) or next_y < 0 or next_y >= len(grid[0]):continue# 如果相鄰格子是陸地且未被訪問,標記并遞歸繼續 DFSif 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 和列數 mn, m = map(int, input().split())# 構建網格:n 行,每行 m 個整數(0 表示水,1 表示陸地)grid = []for _ in range(n):grid.append(list(map(int, input().split())))# 初始化訪問標記表,初始均為 Falsevisited = [[False] * m for _ in range(n)]res = 0 # 統計島嶼數量(連通塊個數)for i in range(n):for j in range(m):# 如果當前位置是陸地,且未被訪問過,則為新的島嶼if grid[i][j] == 1 and not visited[i][j]:res += 1 # 新島嶼計數 +1visited[i][j] = True # 標記起點已訪問dfs(grid, visited, i, j) # DFS 遍歷整塊陸地# 輸出島嶼總數print(res)
廣度優先搜索:只要加入隊列,立即標記該節點走過。
from collections import deque # 使用 deque 作為隊列,提高效率# 定義四個方向:右、下、左、上
directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]def bfs(grid, visited, x, y):"""使用廣度優先搜索(BFS)遍歷并標記一整塊陸地:param grid: 輸入的地圖(二維數組):param visited: 訪問標記矩陣:param x, y: 起始坐標(陸地)"""que = deque()que.append([x, y]) # 將起始節點加入隊列visited[x][y] = True # 標記該點已訪問while que:cur_x, cur_y = que.popleft() # 彈出當前處理的節點for dx, dy in directions: # 遍歷四個方向next_x = cur_x + dxnext_y = cur_y + dy# 越界檢查if next_x < 0 or next_y < 0 or next_x >= len(grid) 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] = Trueque.append([next_x, next_y])def main():# 輸入網格行數 n 和列數 mn, m = map(int, input().split())# 讀取 n 行數據構造 gridgrid = []for i in range(n):grid.append(list(map(int, input().split())))# 初始化訪問標記數組visited = [[False] * m for _ in range(n)]res = 0 # 記錄島嶼數量for i in range(n):for j in range(m):# 遇到未訪問的陸地,開始 BFS,并增加島嶼計數if grid[i][j] == 1 and not visited[i][j]:res += 1bfs(grid, visited, i, j)print(res) # 輸出島嶼數量if __name__ == "__main__":main()
二、島嶼的最大面積(Kamacoder 100)
DFS:
# 四個方向:右、下、左、上(用于搜索相鄰的格子)
position = [[0, 1], [1, 0], [0, -1], [-1, 0]]count = 0 # 用于記錄當前連通塊的陸地面積(全局變量)def dfs(grid, visited, x, y):"""使用深度優先搜索(DFS)標記一整塊陸地并統計面積:param grid: 輸入地圖(二維矩陣):param visited: 訪問標記矩陣:param x, y: 當前坐標"""global count # 使用全局變量記錄當前連通塊的面積for dx, dy in position:cur_x = x + dxcur_y = y + dy# 越界檢查if cur_x < 0 or cur_x >= len(grid) or cur_y < 0 or cur_y >= len(grid[0]):continue# 若是未訪問的陸地,遞歸訪問并增加面積if 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 列
n, m = map(int, input().split())# 構造地圖(鄰接矩陣)
grid = []
for _ in range(n):grid.append(list(map(int, input().split())))# 構造訪問矩陣,記錄哪些節點已訪問
visited = [[False] * m for _ in range(n)]result = 0 # 記錄最大陸地面積(即最大連通塊中1的數量)# 遍歷每一個格子
for i in range(n):for j in range(m):# 遇到一個未訪問的陸地,開始 DFS 并更新最大面積if grid[i][j] == 1 and not visited[i][j]:count = 1 # 初始化當前連通塊的面積visited[i][j] = True # 標記當前格子已訪問dfs(grid, visited, i, j)result = max(result, count) # 更新最大面積# 輸出最大陸地面積
print(result)
BFS:
from collections import deque# 四個方向:右、下、左、上(用于搜索相鄰格子)
position = [[0, 1], [1, 0], [0, -1], [-1, 0]]count = 0 # 記錄當前連通塊面積(使用全局變量)def bfs(grid, visited, x, y):"""廣度優先搜索,對一整塊陸地進行標記并統計面積:param grid: 地圖矩陣:param visited: 訪問標記矩陣:param x, y: 當前陸地坐標"""global count # 使用全局變量記錄當前連通塊面積que = deque()que.append([x, y]) # 將起點入隊while que:cur_x, cur_y = que.popleft() # 彈出隊首元素# 遍歷四個方向for dx, dy in position:next_x = cur_x + dxnext_y = cur_y + dy# 越界處理if next_x < 0 or next_x >= len(grid) or next_y < 0 or next_y >= len(grid[0]):continue# 如果是未訪問的陸地,則入隊并更新訪問記錄與面積if 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 列
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):# 如果當前是未訪問的陸地,則開始BFSif grid[i][j] == 1 and not visited[i][j]:count = 1 # 初始面積為1(當前格子)visited[i][j] = True # 標記已訪問bfs(grid, visited, i, j) # 廣度優先遍歷整塊陸地result = max(result, count) # 更新最大面積# 輸出最大陸地面積
print(result)
三、孤島的總面積(Kamacoder 101)
DFS:先遍歷邊界的陸地將他們變成海洋,然后再統計非邊界的“孤島”面積。
# 四個方向:下、右、上、左
position = [[1, 0], [0, 1], [-1, 0], [0, -1]]
count = 0 # 用于統計當前島嶼面積def dfs(grid, x, y):"""深度優先搜索,沉沒當前島嶼,統計其面積"""global countgrid[x][y] = 0 # 將陸地“沉沒”為水count += 1for i, j in position:next_x = x + inext_y = 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: dfs(grid, next_x, next_y)# 輸入讀取
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: # 左邊界dfs(grid, i, 0)if grid[i][m - 1] == 1: # 右邊界dfs(grid, i, m - 1)for j in range(m):if grid[0][j] == 1: # 上邊界dfs(grid, 0, j)if grid[n - 1][j] == 1: # 下邊界dfs(grid, n - 1, j)# 第二步:統計內部的孤島面積
count = 0 # 重置計數器
for i in range(n):for j in range(m):if grid[i][j] == 1:dfs(grid, i, j)print(count)
這里需要注意:統計內部的孤島面積之前要把計數器count清零,因為遍歷邊界的時候count在dfs函數內部有賦值操作。
BFS:
from collections import deque# 定義四個方向:右、下、左、上(用于遍歷相鄰的陸地)
direct = [[0, 1], [1, 0], [0, -1], [-1, 0]]count = 0 # 用于統計孤島的總面積def bfs(grid, x, y):"""廣度優先搜索:從 (x, y) 開始,將連通的陸地單元格全部“淹掉”(設為0)并累計面積"""global countque = deque()que.append([x, y])grid[x][y] = 0 # 將當前格子標記為已訪問(水)count += 1 # 當前陸地面積 +1while que:x, y = que.popleft()for dx, dy in direct:next_x = x + dxnext_y = y + dy# 越界檢查if next_x < 0 or next_x >= len(grid) or next_y < 0 or next_y >= len(grid[0]):continue# 如果是陸地,則加入隊列,繼續“淹掉”if grid[next_x][next_y] == 1:que.append([next_x, next_y])grid[next_x][next_y] = 0count += 1 # 每找到一個陸地格子,面積 +1# 讀取輸入
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:bfs(grid, i, 0)if grid[i][m - 1] == 1:bfs(grid, i, m - 1)
for j in range(m):if grid[0][j] == 1:bfs(grid, 0, j)if grid[n - 1][j] == 1:bfs(grid, n - 1, j)# 第二步:正式統計所有內部孤島的總面積
count = 0 # 重置計數器
for i in range(n):for j in range(m):if grid[i][j] == 1:bfs(grid, i, j)# 輸出所有孤島的總面積
print(count)
四、沉沒孤島(Kamacoder 102)
DFS:
def dfs(grid, x, y):# 將當前位置標記為2,表示訪問過并來自邊界的陸地grid[x][y] = 2directions = [(-1, 0), (0, -1), (1, 0), (0, 1)] # 上、左、下、右四個方向for dx, dy in directions:nextx, nexty = x + dx, y + dy# 如果越界,則跳過if nextx < 0 or nextx >= len(grid) or nexty < 0 or nexty >= len(grid[0]):continue# 如果是水(0)或已經標記過的陸地(2),也跳過if grid[nextx][nexty] == 0 or grid[nextx][nexty] == 2:continue# 繼續向相鄰陸地遞歸搜索dfs(grid, nextx, nexty)def main():n, m = map(int, input().split()) # 輸入行列數# 讀取整個地圖矩陣grid = [[int(x) for x in input().split()] for _ in range(n)]# 步驟一:處理邊界上的陸地,使用DFS將它們和相連的陸地標記為2for i in range(n):if grid[i][0] == 1: # 左邊界dfs(grid, i, 0)if grid[i][m - 1] == 1: # 右邊界dfs(grid, i, m - 1)for j in range(m):if grid[0][j] == 1: # 上邊界dfs(grid, 0, j)if grid[n - 1][j] == 1: # 下邊界dfs(grid, n - 1, j)# 步驟二和三:# 遍歷所有格子for i in range(n):for j in range(m):if grid[i][j] == 1:# 還剩下的1是被水包圍的孤島,置為0(清除孤島)grid[i][j] = 0elif grid[i][j] == 2:# 原本在邊緣或連通邊緣的陸地,恢復為1grid[i][j] = 1# 打印最終結果矩陣for row in grid:print(' '.join(map(str, row)))if __name__ == "__main__":main()
BFS:
from collections import deque# 輸入地圖的行列數
n, m = list(map(int, input().split()))# 讀取地圖網格 g
g = []
for _ in range(n):row = list(map(int, input().split()))g.append(row)# 定義四個方向(上下左右)
directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
count = 0 # 可選統計被訪問的節點數(未實際使用)# 廣度優先搜索函數,用于將與邊界連通的陸地標記
def bfs(r, c, mode):global count q = deque()q.append((r, c)) # 起始位置加入隊列count += 1while q:r, c = q.popleft()if mode:g[r][c] = 2 # 標記為已訪問(與邊界相連)for di in directions:next_r = r + di[0]next_c = c + di[1]# 越界跳過if next_c < 0 or next_c >= m or next_r < 0 or next_r >= n:continue# 若為陸地(1),則入隊繼續擴展if g[next_r][next_c] == 1:q.append((next_r, next_c))if mode:g[r][c] = 2 # 標記當前格子為邊界連通count += 1# 遍歷邊界四周,找到所有與邊界連通的陸地,并進行 BFS 標記
for i in range(n):if g[i][0] == 1: bfs(i, 0, True) # 左邊界if g[i][m - 1] == 1: bfs(i, m - 1, True) # 右邊界for j in range(m):if g[0][j] == 1: bfs(0, j, True) # 上邊界if g[n - 1][j] == 1: bfs(n - 1, j, True) # 下邊界# 處理最終輸出:
# - 被標記為 2 的陸地(與邊界連通)恢復為 1
# - 其余陸地為封閉島嶼,置為 0(沉沒)
for i in range(n):for j in range(m):if g[i][j] == 2:g[i][j] = 1else:g[i][j] = 0# 打印最終地圖結果
for row in g:print(" ".join(map(str, row)))
五、水流問題(Kamacoder 103)
-
每個 DFS 邏輯是“水可以流向高度大于等于自己的相鄰格子”。
-
從兩個邊界(上/左、下/右)出發分別進行 DFS。
-
最終取兩個集合交集,得到的是能從兩邊都能流到的點。
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] = Trueside.add((i, j)) # 加入當前方向的集合中# 遍歷四個方向for x, y in directions:new_x = i + xnew_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 firstglobal secondN, M = map(int, input().strip().split()) # 輸入矩陣的行數和列數graph = []for _ in range(N):row = input().strip().split()graph.append(row) # 構造二維矩陣# 第一步:從第一邊界(上邊和左邊)出發進行 DFSvisited = [[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)# 第二步:從第二邊界(下邊和右邊)出發進行 DFSvisited = [[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()
六、建造最大島嶼(Kamacoder 104)
-
把每個島嶼編號并計算面積。
-
遍歷所有水域格子,嘗試變成陸地并連接周圍不同的島嶼。
-
記錄最大可能島嶼面積。
-
邊界處理和重復統計都已通過
visited
和set
控制。
import collections# 四個方向:上、右、左、下
directions = [[-1, 0], [0, 1], [0, -1], [1, 0]]area = 0 # 當前島嶼的面積def dfs(i, j, grid, visited, num):"""深度優先搜索,將島嶼上的所有陸地格子標記為同一個編號num,并統計當前島嶼的總面積"""global areaif visited[i][j]:returnvisited[i][j] = Truegrid[i][j] = num # 用編號num標記該島嶼area += 1 # 累加島嶼面積for x, y in directions:new_x = i + xnew_y = j + y# 判斷是否在邊界內且是未訪問的陸地if (0 <= new_x < len(grid)and 0 <= new_y < len(grid[0])and grid[new_x][new_y] == "1"):dfs(new_x, new_y, grid, visited, num)def main():global areaN, M = map(int, input().strip().split()) # 讀入行列數grid = []for _ in range(N):grid.append(input().strip().split()) # 讀取每一行visited = [[False] * M for _ in range(N)] # 記錄訪問情況rec = collections.defaultdict(int) # 記錄每個島嶼編號對應的面積cnt = 2 # 編號從2開始,避免與"0"(水)和"1"(未編號陸地)混淆for i in range(N):for j in range(M):if grid[i][j] == "1":area = 0dfs(i, j, grid, visited, cnt)rec[cnt] = area # 保存當前島嶼面積cnt += 1res = 0 # 最終最大島嶼面積for i in range(N):for j in range(M):if grid[i][j] == "0": # 嘗試將水變成陸地max_island = 1 # 當前面積初始為1(假設這里是陸地)v = set() # 防止重復統計相鄰島嶼for x, y in directions:new_x = i + xnew_y = j + yif (0 <= new_x < len(grid)and 0 <= new_y < len(grid[0])and grid[new_x][new_y] != "0"and grid[new_x][new_y] not in v):max_island += rec[grid[new_x][new_y]]v.add(grid[new_x][new_y])res = max(res, max_island)if res == 0:# 如果沒有水可變為陸地,返回最大島嶼面積return max(rec.values())return resif __name__ == "__main__":print(main())
BFS:
from typing import List
from collections import defaultdictclass Solution:def __init__(self):# 定義四個方向(上、下、左、右)self.direction = [(1,0),(-1,0),(0,1),(0,-1)]self.res = 0 # 存放結果:最大可能的連通面積self.count = 0 # 當前島嶼的面積計數器self.idx = 1 # 當前島嶼的編號,從2開始(因為1已經是初始島嶼標記)self.count_area = defaultdict(int) # 記錄每個島嶼編號對應的面積def max_area_island(self, grid: List[List[int]]) -> int:if not grid or len(grid) == 0 or len(grid[0]) == 0:return 0# Step 1: DFS 標記每個島嶼為不同編號(從 2 開始),并記錄每個島嶼的面積for i in range(len(grid)):for j in range(len(grid[0])):if grid[i][j] == 1:self.count = 0self.idx += 1self.dfs(grid, i, j) # 遞歸標記島嶼# Step 2: 統計每個編號的面積self.check_area(grid)# Step 3: 嘗試將一個 0 變成 1,看是否能連接多個島嶼,獲取最大可能面積if self.check_largest_connect_island(grid=grid):return self.res + 1 # +1 是把0變成1后的面積增加return max(self.count_area.values()) # 若沒有0,返回最大島嶼面積def dfs(self, grid, row, col):# 使用 DFS 給島嶼打編號,并統計面積grid[row][col] = self.idxself.count += 1for dr, dc in self.direction:_row = dr + row _col = dc + col if 0 <= _row < len(grid) and 0 <= _col < len(grid[0]) and grid[_row][_col] == 1:self.dfs(grid, _row, _col)returndef check_area(self, grid):# 遍歷整張圖,統計每個島嶼編號的面積(包含編號為 2 及以上)m, n = len(grid), len(grid[0])for row in range(m):for col in range(n):self.count_area[grid[row][col]] = self.count_area.get(grid[row][col], 0) + 1returndef check_largest_connect_island(self, grid):# 檢查每個值為0的位置,看是否能連接多個島嶼m, n = len(grid), len(grid[0])has_connect = False # 是否存在0可用作連接點for row in range(m):for col in range(n):if grid[row][col] == 0:has_connect = Truearea = 0visited = set() # 避免重復計算同一編號島嶼for dr, dc in self.direction:_row = row + dr _col = col + dcif (0 <= _row < len(grid)and 0 <= _col < len(grid[0])and grid[_row][_col] != 0and grid[_row][_col] not in visited):visited.add(grid[_row][_col])area += self.count_area[grid[_row][_col]]self.res = max(self.res, area) # 更新最大面積return has_connect # 返回是否存在可以轉換的0def main():# 輸入處理m, n = map(int, input().split())grid = []for i in range(m):grid.append(list(map(int, input().split())))# 創建對象并調用主函數sol = Solution()print(sol.max_area_island(grid))if __name__ == '__main__':main()
七、島嶼的周長(Kamacoder 106)
def main():import sysinput = sys.stdin.readdata = input().split()# 讀取行數 n 和列數 mn = int(data[0])m = int(data[1])# 初始化 grid 網格grid = []index = 2 # 從第3個數據開始是地圖數據for i in range(n):# 讀取每一行的 m 個數據grid.append([int(data[index + j]) for j in range(m)])index += msum_land = 0 # 記錄陸地格子的總數cover = 0 # 記錄相鄰的陸地邊對數(每對相鄰邊減少2個周長)for i in range(n):for j in range(m):if grid[i][j] == 1:sum_land += 1 # 統計陸地格子數量# 檢查上方是否是陸地,如果是,說明這兩個格子共享一條邊if i - 1 >= 0 and grid[i - 1][j] == 1:cover += 1# 檢查左方是否是陸地,同樣共享一條邊if j - 1 >= 0 and grid[i][j - 1] == 1:cover += 1# 不檢查下方和右方,是為了避免重復計算邊界# 每個陸地格子原始貢獻 4 個邊界,所有相鄰對共享 2 個邊界result = sum_land * 4 - cover * 2print(result)if __name__ == "__main__":main()