题目描述
思路分析
WA了几发。我现在才知道,list.pop默认是pop(-1),弹出的末尾元素,我一直以为弹出的是队首(手动捂脸哭)
审题,找找思路:
- 题目涉及到:每条路径的安全系数用路径任意位置距离任意小偷最小距离定义。且全部的路径全局最大的安全距离是多少。这种最小最大同时出现的问题,你知道应用使用二分查找。
- 有多个小偷,需要知道每个位置距离最近的小偷的距离,需要使用多源bfs
本题做法如下
-
使用多源bfs,将所有小偷加入队列,然后bfs。
cost_grid[nx][ny] == inf意味着这个位置没被遍历且无小偷,这个条件等价于(nx,ny) not in vis and grid[nx][ny] == 0 -
二分安全系数safe,查看在当前safe下,能否从起点走到终点。(给定safe,任何低于safe的方块都是禁入点,基于此使用bfs判断可达性)
-
最后提一下这个二分模板,这是一个upper_bound模板,找到第一个非法位置需要减一才是最后一个合法位置。
代码
class Solution:
def maximumSafenessFactor(self, grid: List[List[int]]) -> int:
n = len(grid)
if grid[0][0] == 1 or grid[n-1][n-1] == 1:
return 0
cost_grid = [[inf] * n for _ in range(n)]
q = deque()
for i in range(n) :
for j in range(n) :
if grid[i][j] == 1 :
q.append((i,j))
cost_grid[i][j] = 0
dx = [0,0,1,-1]
dy = [1,-1,0,0]
while q :
cur_x,cur_y = q.popleft()
for i in range(4):
nx , ny = cur_x + dx[i] , cur_y + dy[i]
if nx >= 0 and nx < n and ny >= 0 and ny < n and cost_grid[nx][ny] is inf:
q.append((nx,ny))
cost_grid[nx][ny] = cost_grid[cur_x][cur_y] + 1
# 二分
def check(safe: int) -> bool:
# 起点安全系数不足,直接不可行
if cost_grid[0][0] < safe:
return False
vis = [[False] * n for _ in range(n)]
q = deque()
q.append((0, 0))
vis[0][0] = True
while q:
cur_x, cur_y = q.popleft()
# 到达终点,可行
if cur_x == n-1 and cur_y == n-1:
return True
for i in range(4):
nx, ny = cur_x + dx[i], cur_y + dy[i]
# 边界、未访问、安全系数达标
if 0 <= nx < n and 0 <= ny < n and not vis[nx][ny] and cost_grid[nx][ny] >= safe:
vis[nx][ny] = True
q.append((nx, ny))
return False
l , r = 0 , n + n - 1
while l < r :
mid = (l + r) >> 1
# 然后利用mid判断是否可以从左上到右下
if check(mid) :
l = mid + 1
else :
r = mid
return l - 1