zoukankan      html  css  js  c++  java
  • 有向/无向图中搜环

      经常遇到一类问题,提供一个图,判断其中是否含环。所谓的环是一条起点与终点相同的路径(至少含有一条边,两个结点)。由于不带环的连通图和带环的连通图有着本质的区别,不带环的连通图是树,而树相较于一般的图可以支持更多更高效的算法,比如log2(n)时间复杂度内找任意两点的路径信息,在树上进行树形DP等等。

      图按照边是否有向可以分为有向图和无向图。在两类图中找环的时间复杂度均为O(n),而判断是否含环的时间复杂度也是O(n),因此只陈述找环的方法。

    无向图找环

      无向图找环,因为无向图中没有明确的根,我们可以令任意结点为根做DFS操作,每次搜索到一个结点,就修改其状态为已访问,直到搜索到已访问的结点u,这时候通过退栈必定会碰到另外一个u结点,二者之间的路径就是环。

    findLoop(node, father, stack) //node为根结点,father设为空,stack用于记录可能存在的环信息
        stack.push(node)
        if(node.visit)
            return true
        node.visit = true
        for child in node.children
            if(child == father)
                continue
            if(findLoop(child, node, stack))
                return true
        stack.pop()
        return false

      说明正确性。很显然如果我们第二次访问某个结点,很显然两次访问对应的路径必定有相同的根结点(因为无向图的原因DFS会搜索整个连通图中的所有结点),由于DFS每次得到的路径不同,因此我们得到了两条起点相同终点相同的路径,将两条路径首位相连,我们就得到了一个环。如果我们第二次访问相同结点u,那么当前路径中必定包含u,因为在第一次搜索到u时,我们会继续搜索其子树,此时沿着第二条路径逆向走,必定会抵达某个访问过的结点(可能是根),那么若这个结点不是u,就违背了u是第一个被二次访问结点这一前提,故当前路径中必定包含u,两个结点之间的路径中没有重复结点,是一个简单环。

      复杂度非常简单,我们为每个未被访问过的结点调用该方法,每次进入方法,或者修改结点的访问状态,或者找到环,而函数内部的逻辑(不含循环)是常数时间复杂度,循环最多发生|E|次,因此时间复杂度为O(|V|+|E|)。

    有向图找环

      有向图找环相对比较复杂。由于图未必连通(可能由若干连通子图构成),我们需要建立一个公共的根结点r,并从r向图中所有结点建立一条单向边(由于r只有出边,因此r必定不是环的一部分,即不影响我们找到的环)。之后从r出发进行DFS。同样我们需要增加访问状态来避免重复搜索,但是访问两次的结点未必构成环,比如考虑两条路径r->a->b与r->b,很显然a与b之间未必构成环。我们还需要加入一个在栈标志instk,为true表示这个结点在当前路径上,false表示不在。只有搜到的二次访问结点满足该结点在栈中,才能保证其处于环上。  

    findLoop(node, stack)
        if node.visit
            if node.instk == false
                return false
            stack.push(node)
            return true;
        node.visit = true
        node.instk = true
        stack.push(node)
        
        for child in node.children
            if(findLoop(child, stack))
                return true
        
        node.instk = false
        stack.pop()
        return false

      如果图中确实含环,即存在路径u->...->u,那么当我们访问到环上的任意结点u时,由于DFS的缘由,必定会回到自身或是找到另外一个环并退出,无论哪种情况我们都找到了一个环。而如果第一次发现一个结点u被二次访问且在栈中,那么由于该结点在栈中,那么路径中必然包含u,二者之间的路径则形成了环,而由于路径中只含有访问一次的结点(除了u),因此找到的环是简单环。

      时间复杂度与无向图的一致,也是O(|V|+|E|)。

  • 相关阅读:
    ORM的概念, ORM到底是什么
    EM算法
    贝叶斯方法的m-估计
    概率图模型之:贝叶斯网络
    决策树学习
    各种聚类算法的比较
    聚类算法:K均值
    Entity Framework + WCF 远程调用出错
    使用Entity Framework时,序列化出错
    WCF基础知识
  • 原文地址:https://www.cnblogs.com/dalt/p/8401432.html
Copyright © 2011-2022 走看看