深度优先搜索

深度优先搜索是对先序遍历的推广,从某个顶点v开始处理v,然后递归遍历所有和v邻接的顶点,在图中应用深度优先遍历需要注意的问题是图可能有圈,每次访问到一个节点需要标记这个节点是已经访问过的,然后对所有没有被标记的节点递归调用深度优先搜索。深度优先遍历的通用模板如下:

void Dfs(Vertex V)
{
    Visited[V] = True;
    for each W adjacent to V
        if (!Visited[W])
            Dfs(W);
}

若图是无向不连通的,或者是有向非强连通的,那么可能访问不到某些节点,此时需要搜索一个没有被访问过的顶点,对此顶点调用dfs。此算法对每条边访问一次,时间是O(|E|+|V|)

深度优先搜索的应用:

1.无向图

通过遍历无向图,可以生成深度优先生成树,如图

对左边的无向图应用深度优先遍历,从A开始,每一条边(v,w)都在右图中,处理(v,w)的时候,发现w是未标记的,那么用树的一条边表示,若发现w已经标记了,那么画一条虚线,称为背向边,表示这条边不是树的一部分

2.双连通性

若一个连通的无向图中任一顶点删除之后,还是连通的,那么称为双连通的。若一个图不是双连通的,那么将其删除之后导致图不连通的顶点叫做割点,例如,下图是不连通的,C和D是割点:

深度优先搜索提供一个方法找到连通图中的所有割点,深度优先生成树如下图:

方法是,深度优先遍历得到一个编号Num[V],称为先序编号,然后对树中的每个顶点,计算Low[V],这个值是从v开始,最多通过一条背向边能访问到的所有节点Num值的最小值,例如,F能访问到的最高的节点是D,low[F]=Num[D]。Low[V]选择方法是:

1.Num[v]

2.所有背向边(v, w)中的最低Num[w]

3.树的正向边(v, w)中的最低Low[w]

以上三者中的最小值

代码如下:

/* 深度优先遍历分配编号 */
void AssignNum(Vertex V)
{
    Vertex W;
    Num[V] = Counter++;
    Visited[V] = True;
    for each W adjacent to V
        if (!Visited[W])
        {
            Parent[W] = V;
            AssignNum(W);
        }
}

/* 分配Low值 */
void AssignLow(Vertex V)
{
    Vertex W;
    
    /* rule1,直接选Num[W],后面再比较 */
    Low[V] = Num[W];
    for each W adjacent to V
    {
        if (Num[W] > Num[V])
        {
            AssignLow(W);
            if (Low[W] >= Num[V])
                printf("%v is a articulation point", V);
            /* rule3,正向边的最小值 */
            Low[V] = Min(Low[V], Low[W]);
        }
        else if (Parent[V] != W)
            /* rule2,背向边的最小值 */
            Low[V] = Min(Low[V], Num[W]);
    }
}

/* 整合先序和后序两个流程 */
void FindArt(Vertex V)
{
    Vertex W;

    Visited[V] = True;
    Low[V] = Num[W] = Counter++;
    for each W adjacent to V
    {
        if (!Visited[W])
        {
            Parent[W] = V;
            FindArt(W);
            if (Low[W] >= Num[V])
                printf("%v is an articulation point\n", V);
            Low[V] = Min(Low[V], Low[W]);
        }
        else if (Parent[V] != W)
            Low[W] = Min(Low[V], Num[W]);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值