L22 BFS and DFS

Outline:

  • BFS

    • skeleton

    • 证明: v.dis=δ(s,v)

    • BFS树

    • 应用

  • DFS

    • s → all

Ref:

  • 算法设计与分析(Algorithm design and analysis) by 黄宇

BFS

skeleton

  • BFS-WRAPPER(G)

    1
    2
    3
    4
    5
    foreach node v in G do
    v.color := WHITE; v.parent := null; v.dis := +∞;
    foreach node v in G do
    if v.color = WHITE then
    BFS(v);
  • BFS(G)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Initialize an empty queue queNode;
    v.color := GRAY;
    v.dis := 0;
    queNode.ENQUE(v);
    while queNode != empty do
    w := queNode.DEQUE();
    foreach neighbor x of w do:
    if x.color := WHITE then
    x.color := GRAY;
    x.parent := w;
    x.dis := w.dis + 1;
    queNode.ENQUE(x);
    <processing of node w>;
    w.color := BLACK;

证明: v.dis=δ(s,v)

变量v.dis​记录了源点s​到节点v​最短路径的长度,对所有节点依据dis 进行了等价类划分

记源点s到节点v的最短路径长度为δ(s,v),.现在证明v.dis=δ(s,v)

  • 引理5.1 对于有向或无向图G, 对任意边uv​, 有δ(s,v)δ(s,u)+1​​.

    证明:

    如果源点su可达, 则由于uv的存在, sv同样可达. 所以sv最短路径长度必然不超过任意一条sv的路径长度(包括su再到v这条路径), 所以δ(s,v)δ(s,u)+1. 若su不可达, 则δ(s,u)=, 不等式同样成立(当然,若sv也不可达,此时是 +1,同样成立).

  • 引理5.2 从节点s​开始BFS, 在遍历结束时, 对每个可达结点v​, 有 v.disδ(s,v)​​.

    证明:

    采用数学归纳法,对队列上的操作个数归纳, 即证明: 无论队列上执行了多少个操作, 该不变式总是成立: 对于任意v, v.disδ(s,v).

    初始情况是队列执行第一个操作, 即将源点s放入队列中. 此时s.disδ(s,s)=0. 对于其他任意节点v, v.dis=+δ(s,v). 所以初始情况下结论成立.

    由于出队操作对结论没有影响( 出队不会更改 v.dis), 只需要关注入队操作. 假设在处理节点u时, 发现白色邻居v. 根据归纳假设, 有u.disδ(s,u). 对于v, 有: $$ (1)v.dis=u.dis+1(BFS)δ(s,u)+1()δ(s,v)(5.1) $$

    由于v.dis的值一经赋值后不再变化. 所以我们通过归纳法证明了对每个节点v, 有 v.disδ(s,v)


    为了证明相等关系的另一半 v.disδ(s,v)​, 首先要对BFS过程进行更细致的刻画.

  • 引理5.3 假设在BFS过程中, 队列中的元素为<v1,v2,,vr> ( v1是队头, vr​ 是队尾 ). 我们有:

    vi.disvi+1.dis ( 1ir+1 ) , vr.disv1.dis+1

    证明:

    采用数学归纳法,对队列上的操作归纳. 初始情况下, 队列中只有源点s, 结论显然成立. 下面要证明队列任意执行一个操作(出队或入队), 上述结论总是成立.

    假设队头元素v1出队, 则v2成为新的队头元素. 根据归纳假设, 有

    vr.disv1.dis+1v2.dis+1

    v2vr​​的所有元素的小于等于关系依然成立. 所以执行一个出队操作后, 要证明的结论保持成立.

    假设有一个新元素vr+1入队, 此时必然从队首取出一个节点进行处理, 记为u. 在处理u时, 我们发现了白色邻居vr+1并将它放到队列尾部. 此时vr+1.dis=u.dis+1. 在u出队前的时刻, u是队头, v1是队列中的第二个元素, 所以u.disv1.dis. 根据上面的分析, 有 vr+1.dis=u.dis+1v1.dis+1.

    u 出队之前,vr+1未入队时, u是队头, vr​是队尾. 同样根据归纳假设, 有

    vr.disu.dis+1=vr+1.dis 对于队列中其他元素而言, 不等关系未受影响.

    综上, 基于归纳法我们证明了, BFS过程中的任意时刻: vi.disvi+1.dis, 1ir+1vr.disv1.dis+1

  • 定理5.1 假设从图G中的源点s开始对整个图完成BFS, 则对任意节点v, v.dis=δ(s,v), 且从sv由TE组成的路径就是sv的最短路径(不一定是唯一的最短路径)

    证明:

    采用反证法, 假设存在一些节点, 它们的dis值不等于源点到它们的最短路径值. 在这些节点中, 取源点到其距离最短的节点, 记为 v (显然v不可能为s ). 根据引理5.2, 有v.dis>δ(s,v). 注意sv​必然可达, 否则(s,v)=+v.dis

    考察sv的最短路径. 记u为该路径上在v前面的节点, 则 δ(s,v)=δ(s,u)+1. 根据选取v的特定方式, 有u.dis=δ(s,u) (易证). 由此, 有: v.dis>δ(s,v)=δ(s,u)+1=u.dis+1 下面考察节点u刚从队头出队的时刻. 此时节点v可能有三种颜色.

    • 如果v为白色, 则根据BFS框架, 将赋值v.dis=u.dis+1, 这与v.dis>u.dis+1矛盾
    • 如果v为灰色,则记它作为节点w的白色邻居被放到队尾, 且 v.dis=w.dis+1. 由于wv更早离开队列, 所以根据引理5.3, 有v.dis=w.dis+1u.dis+1, 这与v.dis>u.dis+1矛盾
    • 如果v为黑色, 则在u之前它已离开队列, 所以 v.disu.dis, 这与v.dis>u.dis+1矛盾

    证毕.

BFS树

对于边uv

有向 无向
TE v.p=u;v.dis=u.dis+1 同左
BE 0<=v.dis<u.dis nil
DE nil nil
CE v.disu.dis+1 v.dis=u.dis​ 或v.dis=u.dis+1
  • 有向图

    • TE: 当遍历节点 v 时,发现其白色邻居 v, 则 uv​​​​​ 为TE. 在一个连通片内所有TE组成的子图连通无环且包含了该连通片中所有节点. 如果忽略所有边的方向, 则这些TE组成当前连通片的一棵生成树,称为"BFS树"

    • BE: 当遍历节点u时,发现其黑色邻居 v, 且 vu在BFS树中的祖先节点, 则uv​为BE. 对于BE uv, 有 0v.dis<u.dis​​.

    • DE: BFS不可能出现DE。反证假设uv为DE,那么考察在节点u刚出队列,即将处理它的所有邻居的时刻, 节点v的情况:

      • 节点v不可能是白色,否则uv为TE
      • 节点v不可能为灰色, 因为在此时u刚出队列, 而若v为灰色(正在队列中), 这和uv在遍历树上的祖先节点矛盾
      • 节点v不可能是黑色, 在 节点u刚出队的时刻, 如果 节点v已经结束遍历, 这同样和uv​在遍历树上的祖先节点矛盾
    • CE: 当遍历节点u​时,发现其灰色或者黑色邻居 v​, 且v​不是u​的祖先节点( 前面关于DE的讨论证明了必然不可能是子孙节点 ), 则uv​为CE. 对于CE, 有v.disu.dis+1​​

      • 与DFS类似, CE同样可能存在于两个不同的BFS树之间
  • 无向图

    • TE: 与有向图的情况类似, 当遍历节点 v 时,发现其白色邻居 v, 则 uv 为TE. 对于TE(u,v)​, 有 v.dis=u.dis+1. 所有TE组成(当前连通片的)BFS遍历树, 我们为每条TE进行定向, 其方向就是遍历推进的方向.
    • BE: 不存在(证明易)
    • DE: 不存在(证明易)
    • CE: 当遍历节点u​​​时,发现其灰色邻居 v​​​(前面关于BE和DE的讨论证明了v​​​不可能是u​​​的祖先或子孙节点), 则uv​​​为CE. 对于CE, 有 v.dis=u.dis​​​ 或 v.dis=u.dis+1
      • 注意, 此时节点v​不可能是白色,否则uv​为TE; 节点v​不可能是黑色, 否则由于无向边uv​的存在, 在处理u​时, 必然已处理过uv​, 此时的边uv​是二次遍历,直接被剔除, 不做处理.
  • 推论5.1, 对于BFS过程中的CE uv,

    • 无向图 v.dis=u.disv.dis=u.dis+1
    • 有向图 v.disu.dis+1

    证明:( 书上有图)

    对于有向图的CE uv,我们考察v.dis最大可以比u.dis大多少. 注意, 节点v发现得越晚, v.dis越大. 由于图中有边uv的存在, 所以最迟将节点u出队列时, 必将访问节点v. 所以v.disu.dis+1

    对于无向图的CE uv, 当处理u时, 根据前面的讨论, v只能是灰色, 即v在队列中. 根据引理5.3, 有u.disv.disu.dis+1. 所以v.dis=u.disv.dis=u.dis+1

应用

二部图

给定无向图G=(V,E), 我们称之为二分图, 如果存在顶点V的划分V1, V2 ( V1V2=,V1V2=V ), 使得图中任意的边均满足它的一个顶点在 V1,另一个顶点在V2( 即,在V1V2 内部, 任意一对顶点没有边相连 )​​

(等价于二着色问题)

  • 发现TE,推进着色; 发现非TE,检查着色
  • DFS也可以

k度子图

给定无向图G,定义图G的子图H​为k度子图,如果每个顶点的度均大于等于输入的参数k

  • 对于BFS中的点v,若v.d < k( d为v的度数 ), 则v的邻居d--;
  • DFS也可以

DFS

s → all

有向图G,问是否存在点s,s到所有点可达?

  • “可达性”可使用SCC,因为SCC是可达性的等价类。求出G的收缩图后,又由于收缩图是有向无环图。 则检查每个顶点,若存在至少两个顶点出度为0,则不存在; 若仅存在一个出度为0的顶点,则从该顶点出发遍历

  • 对于“all → s”,只需把图转置