很基础的 BFS 题目.

BFS 和 DFS 是相对应的两种算法. 其区别在于对于新发现的可能性, BFS 将其放入队列末尾, 稍后进行探索, 而 DFS 立即探索这种新情况, 等探索完之后再回到之前的状态继续枚举.

对于这道题目来说, 具体来讲, 状况可以用 (位置, 距离, 颜色) 这么一个 tuple 来表示. 最开始的时候, 有 (0, 0, blue) 和 (0, 0, red) 这两种情况. 假设 0到1 有一条蓝边, 0到2 有一条红边, 那么新的情况是 (1, 1, red) 和 (2, 1, blue).

如果我们使用 DFS, 那么当新发现 (1, 1, red) 这个状态的时候, 我会立即以 (1, 1, red) 为起点, 继续探索 1 号点的邻居, 比如找到了 (3, 2, blue) … 直到找完所有通过 (1, 1, red) 可以达到的状态之后, 再继续以 (2, 1, blue) 为基础进行枚举.

而 BFS 不同. BFS 会将 (3, 2, blue) 放到一个队列 q末尾, 然后假装什么都没发生过, 继续从 q队首 拿一个状态出来, 枚举它的邻居, 以此往复.

这样做的好处是, BFS 队列 q 中的所有状态一定是按距离升序排列的. 一但某个 (顶点, 颜色) 对出现在 q 中, 那么它一定是从起点到该顶点且下一步是该颜色的最短距离. 所以如果后面再遇到该 (顶点, 颜色) 对, 就可以不进行枚举了. 从而节省极大的时间.

下面是一个例子

如果使用 DFS, 那么一个搜索顺序如下:

(0, 0, blue) 
    (1, 1, red) 
        (3, 2, blue)
    回到(1, 1, red) 
        (4, 2, blue) 
    回到(1, 1, red)
回到(0, 0, blue) 
继续 (0, 0, red) 
   (2, 1, blue) 
       (4, 2, red) 
    回到(2, 1, blue) 
       (5, 2, red) 
    回到(2, 1, blue) 
回到(0, 0, red) 
结束

如果使用 BFS, 那么一个搜索顺序如下:

(0, 0, blue) # 使 (1, 1, red) 加入到队尾
(0, 0, red)  # 使 (2, 1, blue) 加入到队尾
(1, 1, red) # 使 (3, 2, blue), (3, 4, blue) 加入到队尾
(2, 1, blue) # 使 (4, 2, red), (5, 2, red) 加入到队尾
(3, 2, blue) # 没新的状态可加了 下同
(3, 4, blue)
(4, 2, red)
(5, 2, red)
结束

下面是代码链接

在代码中, 我使用节点编号 kk+n 分别代表下一步该走蓝边还是红边.

代码链接