优化带规则网格的寻路算法:大网格性能提升需求
问题描述
给定带数值的网格,需找到从最高点到最低点的最长路径(最缓路径)。参考的递归搜索代码在小网格上运行正常,但在140x140这类大网格中,因遍历所有可能路径导致计算耗时极长,需要实现剪枝策略停止对非最优路径的搜索。
原递归代码如下:
def find_paths_recursive(grid, current_path=[(136,136)], solutions=[]): n = len(grid) dirs = [(-1,0), (1,0), (0,1), (0,-1)] last_cell = current_path[-1] for x,y in dirs: new_i = last_cell[0] + x new_j = last_cell[1] + y # 检查新单元格是否在网格内 if new_i<0 or new_i>=n or new_j<0 or new_j>=n: continue # 检查新单元格数值是否大于当前单元格 if grid[new_i][new_j] > grid[last_cell[0]][last_cell[1]]: continue # 检查新单元格是否已在路径中 if (new_i, new_j) in current_path: continue # 复制当前路径并添加新单元格 current_path_copy = current_path.copy() current_path_copy.append((new_i, new_j)) # 到达终点则保存路径 if new_i==0 and new_j ==0: solutions.append(current_path_copy) print(current_path_copy) # 递归搜索新路径 find_paths_recursive(grid, current_path_copy, solutions) return solutions def compute_cell_values(grid1, solutions): path_values = [] for solution in solutions: solution_values = [] for cell in solution: solution_values.append(grid1[cell[0]][cell[1]]) path_values.append(solution_values) return path_values grid1 = [...] solutions = find_paths_recursive(grid1) path_values = compute_cell_values(grid1, solutions) print('所有路径:') print(solutions) print('路径数值:') print(path_values)
剪枝与优化方案
1. 记忆化搜索(核心剪枝)
记录每个单元格(i,j)能到达终点的最长路径长度。当遍历到(i,j)时,如果当前路径长度已经小于等于该单元格已记录的最长路径,直接终止该分支搜索——因为继续走下去也不可能得到更长的路径。
2. 仅跟踪最长路径,丢弃非最优解
原代码保存所有路径会占用大量内存且无必要,只需维护当前找到的最长路径及其长度,一旦发现当前路径长度不可能超过已知最长路径,立即剪枝。
3. 启发式剪枝:提前预判路径上限
计算当前路径长度加上从当前单元格到终点的曼哈顿距离(即|i-0| + |j-0|,每步最多走一格,这是理论上能走的最大步数),如果这个值小于当前已知的最长路径长度,直接终止该分支——即使走满所有可能步数也追不上当前最优解。
4. 优先搜索更有潜力的方向
优先搜索与当前单元格数值差更小的邻居(符合"最缓"路径需求),或者更靠近终点的邻居。这样能更快找到较长路径,进而更早触发剪枝,减少无效搜索。
优化后的代码
def find_longest_path(grid, start, end): n = len(grid) dirs = [(-1,0), (1,0), (0,1), (0,-1)] # 记忆化数组:memo[i][j] 记录从(i,j)到终点的最长路径长度 memo = [[-1 for _ in range(n)] for _ in range(n)] longest_path = [] def dfs(current_i, current_j, current_path): nonlocal longest_path # 到达终点,更新最长路径 if (current_i, current_j) == end: if len(current_path) > len(longest_path): longest_path = current_path.copy() return len(current_path) # 已有更优路径记录,直接返回并剪枝 if memo[current_i][current_j] != -1: if len(current_path) + memo[current_i][current_j] - 1 <= len(longest_path): return memo[current_i][current_j] max_length = len(current_path) # 按数值差从小到大排序邻居,优先走更缓的路径 neighbors = [] for dx, dy in dirs: ni, nj = current_i + dx, current_j + dy if 0 <= ni < n and 0 <= nj < n: if grid[ni][nj] <= grid[current_i][current_j] and (ni, nj) not in current_path: diff = grid[current_i][current_j] - grid[ni][nj] neighbors.append((diff, ni, nj)) # 优先搜索数值差更小的方向 neighbors.sort() for _, ni, nj in neighbors: current_path.append((ni, nj)) # 启发式剪枝:当前路径+剩余最大可能步数仍小于已知最长,直接跳过 remaining_steps = abs(ni - end[0]) + abs(nj - end[1]) if len(current_path) + remaining_steps <= len(longest_path): current_path.pop() continue length = dfs(ni, nj, current_path) if length > max_length: max_length = length current_path.pop() # 更新记忆化数组 memo[current_i][current_j] = max_length return max_length dfs(start[0], start[1], [start]) return longest_path def compute_cell_values(grid, path): return [grid[i][j] for (i,j) in path] # 示例使用 grid1 = [...] # 你的网格数据 start_point = (136, 136) # 最高点坐标 end_point = (0, 0) # 最低点坐标 longest_path = find_longest_path(grid1, start_point, end_point) path_values = compute_cell_values(grid1, longest_path) print('最长路径:', longest_path) print('路径数值:', path_values)
优化效果说明
- 记忆化搜索避免了重复计算同一单元格的路径分支,大幅减少递归次数。
- 启发式剪枝提前终止了不可能成为最优解的路径分支。
- 优先搜索更缓方向能更快找到较长路径,更早触发剪枝逻辑。
- 仅跟踪最长路径节省了大量内存,避免大网格下的内存溢出问题。
内容的提问来源于stack exchange,提问作者D a r k k
相关产品推荐
相关产品推荐

