如何在给定一组边缘的情况下检查是否形成无向循环及其复杂性是什么?

时间:2017-10-12 10:33:31

标签: algorithm graph

我只给了一组边,并询问图中是否有一个循环(图可能没有连接)。我知道使用简单的DFS可以很容易地解决它。但我想知道是否有任何其他方法降低了复杂性,因为我可能会收到多个此类查询以检查周期并且每次运行dfs都会产生O(nq)复杂度,n个边数和q个查询数。 / p>

1 个答案:

答案 0 :(得分:2)

您可以使用不相交集,它可以找到O(E)中的所有周期(E是边数)

它的作用:

  1. 跟踪直接或间接连接的节点 (意思是两个节点在同一组中)。

  2. 将两个节点放在同一个集合中。 (意思是他们 连接的)。实际上,它确实是这两个节点来自的两个集合的联合。

  3. Disjoint set在O(1)中执行这两项操作。 以下是我使用路径压缩实现Disjoint set的方法:

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    // This array is used to represent a backward tree (Forest actually)
    // all nodes part of a tree are in the same set
    int disjointset[1000];
    
    // at first all nodes are separated
    // that is they are part of a 1 element set
    void initialize(int n){
        for(int i= 0; i<=n; i++){
            disjointset[i]= i;
        }
    }
    
    // get the root parent of node a in disjoint tree structure
    int getParent(int a){
        if(disjointset[a] == a)
            return a;
    
        // we do this assignment to shorten the path from this node to it's top ancestor in tree
        // this is called path compression
        disjointset[a] = getParent(disjointset[a]);
    
        return disjointset[a];
    }
    
    // check if two nodes are directly/indirectly connected
    bool connected(int a, int b){
        return getParent(a) == getParent(b);
    }
    
    // join two nodes a and b, after this they will be connected
    void join(int a, int b){
        disjointset[getParent(a)] = getParent(b);
    }
    
    int main(){
        //freopen("F:/input.txt", "r", stdin);
    
        // n nodes, e edges
        int n, e, u, v;
    
        cin>>n>>e;   // e number of edges
    
        //initialize the backward tree of disjoint set
        initialize(n);
    
        for(int i= 0; i<e; i++){
            cin>>u>>v;
    
            if(connected(u, v)){
                cout<< "Cycle found"<<endl;
            }
    
            join(u,v);
        }
    
    }
    
    
    /*
    
    //sample input
    //6 nodes 6 edges
    6 6
    1 2
    2 3
    1 3
    3 4
    3 5
    4 6
    
    */
    

    注意:多次插入相同的边将被视为一个循环。