算法导论22.3深度优先搜索 练习总结 (转载)

22.3-1 画一个 3*3 的网格,行和列的抬头分别标记为白色、灰色和黑色,对于每个表单元 (i, j),请指出对有向图进行深度优先搜索的过程中,是否可能存在一条边,链接一个颜色为 i 的结点和一个颜色为 j 的结点。对于每种可能的边,指明该种边的类型。另外,请针对无向图的深度优先搜索再制作一张这样的网格。

ANSWER:

 

22.3-2 给出深度优先搜索算法在图 22-6 上的运行过程。假定深度优先搜索算法的第 5~7 行的 for 循环是以字母表顺序依次处理每个结点,假定每条邻接链表皆以字母表顺序对立面的结点进行了排序。请给出每个结点的发信啊时间和完成时间,并给出每条边的分类。

ANSWER:

 

22.3-3 给出图 22-4 的深度优先搜索的括号化结构。

ANSWER:

 

22.3-4 证明:使用单个位来存放每个结点的颜色已经足够。这一点可以通过证明如下事实来得到:如果将 DFS-VISIT 的第 8 行删除,DFS 给出的结果相同。

ANSWER:和 22.2-3 类似,事实上,在 DFS-VISIT 中,在递归过程中,系统会调用栈存放未被检测的结点,并不一定需要将结点着黑色和灰色来区别,因为程序中并没有检测结点是否黑色的命令。着黑白灰是为了易于观察。

 

22.3-5 证明边 (u, v) 是:

a. 树边或前向边当且仅当 u.d < v.d < v.f < u.f。

b. 后向边当且仅当 v.d ≤ u.d < u.f ≤ v.f。

c. 横向边当且仅当 v.d < v.f < u.d < u.f。

ANSWER:由于深度优先搜索满足括号化结构,将结点的关系以括号化结构表示易证明此关系。

 

22.3-6 证明:在无向图中,根据深度优先搜索算法是先搜索 (u, v) 还是先搜索 (v, u) 来将边 (u, v) 分类为树边或者后向边,与根据分类列表中的 4 种类型的次序进行分类是等价的。

ANSWER:有向图是将无向图的一条边变成有方向的两条边。所以本质上分类标准是等价的。

 

22.3-7 请重写 DFS 算法的伪代码,以便使用栈来消除递归调用。

ANSWER:

 

DFS-VISIT:
    STACK.push(u)
    while ! STACK.empty
        u = STACK.top
        if u.color == GRAY
            u.color = BLACK
            time = time + 1
            u.f = time
            STACK.pop
            continue
        if u.color == WHITE
            u.color = GRAY
            time = time + 1
            u.d = time
        for each v ∈ G:Adj[u]
            v.π = u
            STACK.push(u)

 

 

22.3-8 请给出如下猜想的一个反例:如果有向图 G 包含一条从结点 u 到结点 v 的路径,并且在对图 G 进行深度优先搜索时有 u.d < v.d,则结点 v 是结点 u 在深度优先森林中的一个后代。

ANSWER:

 

22.3-9 请给出如下猜想的一个反例:如果有向图 G 包含一条从结点 u 到结点 v 的路径,则任何对图 G 的深度优先搜索都将导致 v.d ≤ u.f。

ANSWER:和 22.3-8 反例的图一样。

 

22.3-10 修改深度优先搜索的伪代码,让其打印出有向图 G 的每条边及其分类。并指出,如果图 G 是无向图, 要进行何种修改才能达到相同的效果。

ANSWER:在完成 DFS 之后对有向图 G 的边进行遍历,按照 22.3-5的结论的规则。

 
CLASSIFY-EDGE(G):
    for each vertex u ∈ G.V
        for each v ∈ G:Adj[u]
            if v.π == u:
                edge(u, v).c = T
            else if u.d < v.d < v.f < u.f :
                edge(u, v).c = F
            else if v.d ≤ u.d < u.f ≤ v.f:
                edge(u, v).c = B
            else:
                edge(u, v).c = C
View Code

 

无向图:只需要把三个 else 改成一个 else,分类为后向边即可。

22.3-11 请解释有向图的一个结点 u 怎样才能成为深度优先树中的唯一结点,即使结点 u 同时有入边和出边。

ANSWER:

 

22.3-12 证明:我们可以在无向图 F 上使用深度优先搜索来获得图 G 的连通分量,并且深度优先森林所包含的数的棵数与 G 的连通分量数量相同。更准确地说,请给出如何修改深度优先搜索来让其每个结点赋予一个介于 1 和 k 之间的整数值 v.cc,这里 k 是 G 的连通分量数,使得 u.cc = v.cc 当且仅当结点 u 和结点 v 处于同一个连通分量中。

ANSWER:当执行 DFS 的第 5、6 行时,每跳入一次第 7 行,连通分量数加 1,在 DFS-VISIT 里遇到的结点的联通分量数相同。

 联通分支的数量用ceil表示,代码修改如下

void Link_Graph::DFS()
{
    int u, ceil = 0;
    //对每个顶点初始化
    for(u = 1; u <= n; u++)
    {
        V[u].color = WHITE;
        V[u].p =  NULL;
    }
    //时间戳初始化
    time = 0;
    //依次检索V中的顶点,发现白色顶点时,调用DFS_Visit访问该顶点
    for(u = 1; u <= n; u++)
    {
        if(V[u].color == WHITE)
        {
            ceil++;
            DFS_Visit(u, ceil);
        }
    }
}

void Link_Graph::DFS_Visit(int u, int ceil)
{
    int v;
    Edge *e;
    //将u置为灰色
    V[u].color = GRAY;
    //使全局变量time增值
    time++;
    //将time的新值记录为发现时间
    V[u].d = time;
    e = V[u].head;
    while(e)
    {
        v = e->end;
        //如果顶点为白色
        if(V[v].color == WHITE)
        {
            //递归访问顶点
            V[v].p = u;
            DFS_Visit(v, ceil);
            //树边
            e->type = TREE;
        }
        else if(V[v].color == GRAY)
        {
            //反向边
            e->type = BACK;
        }
        else if(V[v].color == BLACK)
        {
            //正向边
            if(V[u].d < V[v].d)
                e->type = FORWARD;
            //交叉边
            else
                e->type = CROSS;
        }
        e = e->next;
    }
    //以u为起点的所有边都被探寻后,置u为黑色
    V[u].color = BLACK;
    V[u].ceil = ceil;
    //并将完成时间记录在f[u]中
    time++;
    V[u].f = time;
}
View Code

 

*22.3-13 对于有向图 G = (V, E) 来说,如果 u ~ v 以为这图 G 至多包含一条从 u 到 v 的简单路径,则图 G 是单连通图。请给出一个有效算法来判断一个有向图是否单连通图。

ANSWER:

单连通图没有正向边(向前边)

posted @ 2017-08-23 16:10  miaoheping  阅读(1856)  评论(0编辑  收藏  举报