题目地址:全球变暖
此题为“寻找一个解”,又是这种图形式的,所以我们使用深度优先遍历DFS。
全题思路:题目中所求的是照片中有多少岛屿会被完全淹没,即全部的岛屿 - 留下的岛屿,所以我们可以for循环遍历所有点,对每个点进行判断此点是否在为未淹没的岛屿上,并在循环的同时记录原本有多少个岛屿。
1.先写入数据和模板:
n = int(input())
highlands = 0 # 高地,代表不能被淹没
islands = 0 # 所有的岛屿
note = [[0] * n for _ in range(n)] # 设置临时数组
picture = []
move = [[1, 0], [-1, 0], [0, 1], [0, -1]] # 进行上下左右移动
for i in range(n):
picture.append(input())
def DFS(x, y):
pass
for x in range(1,n - 1):
for y in range(1, n - 1):
if picture[x][y] == '#' and note[x][y] == 0:
DFS(x, y)
print(islands - highlands)
2.对于是否为高地的判断较为简单,判断此点上下左右均为‘#’即可:
if picture[x + 1][y] == '#' and picture[x - 1][y] == '#' and picture[x][y + 1] == '#' and picture[x][y - 1] == '#': # 找到高地
highlands += 1
3.对点进行回溯遍历:
for i in range(4):
xx = x + move[i][0]
yy = y + move[i][1]
if picture[xx][yy] == '#' and note[xx][yy] == 0: # 若此点为陆地且未被访问过
DFS(xx, yy)
4.对代码进行补充:
n = int(input())
highlands = 0
islands = 0
note = [[0] * n for _ in range(n)]
picture = []
move = [[1, 0], [-1, 0], [0, 1], [0, -1]]
for i in range(n):
picture.append(input())
def DFS(x, y):
global highlands
if note[x][y] == 1:
return
note[x][y] = 1 # 记录已经遍历过
if picture[x + 1][y] == '#' and picture[x - 1][y] == '#' and picture[x][y + 1] == '#' and picture[x][y - 1] == '#': # 找到高地
highlands += 1
for i in range(4):
xx = x + move[i][0]
yy = y + move[i][1]
if picture[xx][yy] == '#' and note[xx][yy] == 0:
DFS(xx, yy)
for x in range(1,n - 1):
for y in range(1, n - 1):
if picture[x][y] == '#' and note[x][y] == 0:
DFS(x, y)
print(islands - highlands)
5.补充后会发现我们只是找到了高地,但是对于全部岛屿的数量我们并没有找到,但如果在DFS函数内寻找原来全部的岛屿并不好找,所以我们在函数外来寻找,此时我们注意到下面两层for循环中是遍历picture的,当其进入循环时即代表找到了一做岛屿,不管其是否能被淹没,所以:
for x in range(1,n - 1):
for y in range(1, n - 1):
if picture[x][y] == '#' and note[x][y] == 0:
islands += 1
DFS(x, y)
此时还不能AC,因为在回溯的过程中,highlands点不止存在一个,可能一个岛屿上存在多个highlands点,所以我们提前设立flag来确认此岛屿是否能被淹没。
n = int(input())
highlands = 0
islands = 0
note = [[0] * n for _ in range(n)]
flag = 0 # 防止回溯时重复确认highlands,1代表不能被淹没,0代表能被淹没
picture = []
move = [[1, 0], [-1, 0], [0, 1], [0, -1]]
for i in range(n):
picture.append(input())
def DFS(x, y):
global flag
global highlands
if note[x][y] == 1:
return
note[x][y] = 1 # 记录已经遍历过
if flag == 0: # 判断其是否能被淹没
if picture[x + 1][y] == '#' and picture[x - 1][y] == '#' and picture[x][y + 1] == '#' and picture[x][y - 1] == '#': # 找到高地
highlands += 1
flag = 1 # 不能被淹没,当再次在此岛屿遍历时不必再寻找highlands点
for i in range(4):
xx = x + move[i][0]
yy = y + move[i][1]
if picture[xx][yy] == '#' and note[xx][yy] == 0:
DFS(xx, yy)
for x in range(1,n - 1):
for y in range(1, n - 1):
if picture[x][y] == '#' and note[x][y] == 0:
islands += 1
flag = 0 # 假设其能够被淹没
DFS(x, y)
print(islands - highlands)
为什么在确认flag=1后不能直接return呢?因为即使确定了我们也要将此岛屿的其他点遍历一遍,防止下一次for循环再次遍历这座已经遍历过的岛屿,导致islands过多。
此时能够AC了吗?并不能,你会发现有两个案例会出现段错误,经过一个多小时的寻找发现,Python自身存在默认递归深度≈1000,但是1000的深度完全不够此题深度,所以我们在最前面改变其默认递归深度:
import sys
sys.setrecursionlimit(1000000) # 将递归深度改为1000000
完整AC代码:
sys.setrecursionlimit(1000000) # 修改深度限制,否则会出现段错误!!!
n = int(input())
highlands = 0
islands = 0
note = [[0] * n for _ in range(n)]
flag = 0 # 防止回溯时重复确认highlands
picture = []
move = [[1, 0], [-1, 0], [0, 1], [0, -1]]
for i in range(n):
picture.append(input())
def DFS(x, y):
global flag
global highlands
if note[x][y] == 1:
return
note[x][y] = 1 # 记录已经遍历过
if flag == 0:
if picture[x + 1][y] == '#' and picture[x - 1][y] == '#' and picture[x][y + 1] == '#' and picture[x][y - 1] == '#': # 找到高地
highlands += 1
flag = 1
for i in range(4):
xx = x + move[i][0]
yy = y + move[i][1]
if picture[xx][yy] == '#' and note[xx][yy] == 0:
DFS(xx, yy)
for x in range(1,n - 1):
for y in range(1, n - 1):
if picture[x][y] == '#' and note[x][y] == 0:
islands += 1
flag = 0
DFS(x, y)
print(islands - highlands)