You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带扩展单元格的旅行图多源BFS问题求解咨询

嘿,我来帮你搞定这个网格扩展的问题!你之前用多源BFS的思路方向是对的,但状态设计里缺了对扩展次数的跟踪,也没提前判断扩展/移动的合法性,所以才会卡壳。咱们一步步拆解调整:

先理清楚核心规则

首先得把题目里的规则嚼透,不然思路容易跑偏:

  • 你控制的探索者从任意起点出发,每单位时间能上下左右走一格,走到的单元格会被标记为已占用。
  • 每累计过T单位时间,所有已占用的单元格会集体向四方向扩展一圈(也就是每个已占用格的上下左右都变成已占用)。
  • 不管是探索者移动到了不可访问区域/网格外,还是扩展出来的单元格碰到了这些非法区域,整个过程直接停止,最后统计所有被占用过的不同单元格总数。
调整你的BFS状态设计

你之前的[M][M][K]状态只记录了位置和距下次扩展的剩余时间,这不够。咱们把状态改成**(x, y, remaining_time, expand_count)**:

  • x,y:探索者当前的位置
  • remaining_time:距离下一次扩展还剩多少时间(范围0到T-1)
  • expand_count:已经完成了多少次扩展
    这个状态能帮你精准跟踪什么时候要触发扩展,以及当前的扩展轮次,方便判断后续操作是否合法。
关键的合法性判断逻辑

这是解决问题的核心,分两种情况处理:

1. 移动时的合法性判断

当探索者要移动到相邻单元格(nx, ny)时:

  • 先检查(nx, ny)是不是在网格范围内,而且不是不可访问单元格。要是不满足,说明移动后直接触发停止条件,这个路径就别往下走了。
  • 要是合法,就把(nx, ny)标记为已占用(没标记过的话),然后生成新状态:(nx, ny, remaining_time-1, expand_count)(因为过了1单位时间,剩余时间减1)。

2. 扩展时的合法性判断

当remaining_time == 0时,下一个时间单位就要触发扩展了,这时候得提前预判这次扩展会不会踩雷:

  • 咱们可以提前给每个单元格算个max_expand值:这个值代表以该单元格为中心,最多能向外扩展多少次而不碰到障碍或边界。比如边界单元格或不可访问单元格的max_expand是0,内部单元格的max_expand等于它四个邻居的max_expand最小值加1(用多源BFS就能快速算出这个矩阵)。
  • 然后,全局的最大可扩展次数是所有已占用单元格的max_expand中的最小值。如果下一次扩展的次数(expand_count+1)超过了这个最小值,说明扩展后会碰到非法区域,直接停止这个路径的后续操作。
  • 要是扩展合法,就把所有已占用单元格的四方向相邻格标记为已占用(注意去重),然后生成新状态:(x, y, T-1, expand_count+1)(扩展消耗了1单位时间,剩余时间重置为T-1)。
优化技巧(应对M=1000的大网格)
  • 预处理max_expand矩阵:用多源BFS一次性算出所有单元格的最大可扩展次数,避免每次判断扩展合法性时遍历整个网格。
  • 状态去重:用一个三维数组visited[x][y][remaining_time],记录该位置在剩余时间为remaining_time时已经达到的最大扩展次数。如果当前状态的expand_count不大于记录的次数,就跳过这个状态,避免重复处理。
  • 维护全局最小max_expand:不用每次遍历整个网格找全局最小,而是在每次标记新的已占用单元格时,更新全局的最小max_expand值,这样能大幅提升效率。
伪代码参考
def calculate_occupied_cells(M, grid, starts, T):
    # grid: 0=可占用,1=不可访问
    occupied = [[False]*M for _ in range(M)]
    # 预处理每个单元格的最大可扩展次数max_expand
    max_expand = [[0]*M for _ in range(M)]
    from collections import deque
    q = deque()
    # 边界和不可访问单元格的max_expand为0,加入队列初始化
    for i in range(M):
        for j in range(M):
            if grid[i][j] == 1 or i in (0, M-1) or j in (0, M-1):
                max_expand[i][j] = 0
                q.append((i, j))
            else:
                max_expand[i][j] = -1  # 未初始化标记
    dirs = [(-1,0), (1,0), (0,-1), (0,1)]
    # 多源BFS计算max_expand
    while q:
        x, y = q.popleft()
        for dx, dy in dirs:
            nx, ny = x+dx, y+dy
            if 0<=nx<M and 0<=ny<M and max_expand[nx][ny] == -1:
                max_expand[nx][ny] = max_expand[x][y] + 1
                q.append((nx, ny))
    # 初始化BFS队列,状态为(x,y,剩余时间,已扩展次数)
    bfs_q = deque()
    # visited[x][y][剩余时间] 记录该状态下的最大扩展次数,避免重复处理
    visited = [[[-1]*T for _ in range(M)] for _ in range(M)]
    # 初始化全局最小max_expand
    global_min_expand = float('inf')
    for sx, sy in starts:
        occupied[sx][sy] = True
        bfs_q.append((sx, sy, T-1, 0))
        visited[sx][sy][T-1] = 0
        if max_expand[sx][sy] < global_min_expand:
            global_min_expand = max_expand[sx][sy]
    total = len(starts)
    while bfs_q:
        x, y, remaining, expand = bfs_q.popleft()
        # 处理移动操作
        for dx, dy in dirs:
            nx, ny = x+dx, y+dy
            if 0<=nx<M and 0<=ny<M and grid[nx][ny]==0 and not occupied[nx][ny]:
                occupied[nx][ny] = True
                total +=1
                # 更新全局最小max_expand
                if max_expand[nx][ny] < global_min_expand:
                    global_min_expand = max_expand[nx][ny]
                new_remaining = remaining -1
                new_expand = expand
                # 状态去重判断
                if visited[nx][ny][new_remaining] < new_expand:
                    visited[nx][ny][new_remaining] = new_expand
                    bfs_q.append((nx, ny, new_remaining, new_expand))
        # 处理扩展操作(剩余时间为0时触发)
        if remaining == 0:
            if expand +1 > global_min_expand:
                # 扩展会触发停止条件,跳过
                continue
            # 执行扩展,收集所有新的可占用单元格
            temp_new = set()
            for i in range(M):
                for j in range(M):
                    if occupied[i][j]:
                        for dx, dy in dirs:
                            ni, nj = i+dx, j+dy
                            if 0<=ni<M and 0<=nj<M and grid[ni][nj]==0 and not occupied[ni][nj]:
                                temp_new.add((ni, nj))
            # 标记新单元格并更新总数
            for ni, nj in temp_new:
                occupied[ni][nj] = True
                total +=1
                if max_expand[ni][nj] < global_min_expand:
                    global_min_expand = max_expand[ni][nj]
            # 生成新状态
            new_remaining = T-1
            new_expand = expand +1
            if visited[x][y][new_remaining] < new_expand:
                visited[x][y][new_remaining] = new_expand
                bfs_q.append((x, y, new_remaining, new_expand))
    return total

这个伪代码里已经优化了全局最小max_expand的维护,不用每次遍历整个网格,而且状态去重也做了处理,应对M=1000的大网格也没问题。

内容的提问来源于stack exchange,提问作者cracra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:39:14