双向广度优先搜索 (Bidirectional BFS)

基于双队列由两端交替波纹扩张,将搜索指数项从 $O(b^d)$ 瞬间收紧至 $O(2 \cdot b^{d/2})$

📖 算法原理:双端扩张与交点碰头定理

宽度优先搜索 (BFS) 在寻找无权图最短路径时极为经典。然而,若起点到终点距离为 $d$,分叉数为 $b$,单向 BFS 需要探索的体积为 $O(b^d)$(即以起点为中心画一个巨大圆盘)。

📐 双向搜索(Bidirectional BFS)空间对折机制

双向 BFS 同时自起点(正向波)与终点(反向波)两端建立独立队列交替进行 BFS 扩散。当两个探索前沿在树或图的某处碰头(交汇)时,最短路径即被确定:

  • 空间几何对比:它相当于在两端分别画了两个半径为 $d/2$ 的小圆盘。其总体探索状态数降为 $O(2 \cdot b^{d/2})$!
  • 双队列交替策略(优化):在每一次步骤中,算法会优先选择节点数较小的那个队列进行单步扩展。这保证了两端波纹能以最均匀、开销最小的方式在正中完美交汇。
点击"开始同步演示"观察左右同屏下的盲目单向搜索与高效双端对折搜索的几何图形开销对比。
🔴 左屏:单向 BFS (盲目铺满)
已扫描节点0
队列等待0
路径步数0
🟢 右屏:双向 BFS (双端对合)
已扫描节点0
正向/反向队列0 / 0
路径步数0
int bidirectionalBFS() {
    queue<int> q_f, q_b; // 正向和反向队列
    q_f.push(start); vis_f[start] = 1;
    q_b.push(end);   vis_b[end] = 1;
    
    while (!q_f.empty() && !q_b.empty()) {
        // 核心优化:优先扩展当前节点数较小的队列 front
        if (q_f.size() <= q_b.size()) {
            if (expand(q_f, vis_f, vis_b)) return step;
        } else {
            if (expand(q_b, vis_b, vis_f)) return step;
        }
    }
}
bool expand(queue<int>& q, int* self_vis, int* other_vis) {
    int curr = q.front(); q.pop();
    for (int next : adj[curr]) {
        if (other_vis[next]) {
            return true; // 💥 交汇点碰头,寻路达成!
        }
        if (!self_vis[next]) {
            self_vis[next] = 1; q.push(next);
        }
    }
    return false;
}
📋 寻路步骤同步日志