简体   繁体   中英

Detecting a cycle in a compressed directed graph?

I'm learning for the exam, and can't manage with this problem:

We are given a graph with n <= 300 000 nodes, but in compressed form. This form consists of m <= 300 000 lines, each given by three numbers: a_i, b_i, c_i which means that there are directed edges from node a_i to all nodes from the interval [b_i, c_i]. The problem is to decide if there exists a cycle in a given graph, or no.

For example input: (numbers n,m and then m lines that describe graph)

4 5

1 2 3

1 4 4

2 3 4

3 4 4

4 1 1

The answer is YES (for example cycle: 1->2->3->4->1)

and for this input:

4 4

1 2 3

1 4 4

2 3 4

3 4 4

the answer is NO.

So the main problem is that this graph can be really huge and I can't afford creating it and running DFS. It has to be done much faster. My first idea was to use Topological sorting algorithm. If it works then there is no cycle in a given graph, otherwise there is a cycle. But it is difficult to update degrees of nodes (in order to select node with deg_in = 0 in each step of this algorithm). I was thinking maybe using interval tree will help with that - when I'm deleting node v, I can see his adjacency list (elements of this list would be given intervals) and for all intervals decrement deg_in of those points. So I can check what is some node degree in logarithmic time but I still can't update the list of nodes with deg_in = 0 fast. I don't know, maybe I'm trying a solution that cannot be fixed?

Can anybody help?

I will try to make a meta code for the algorithm. This will be a special case of the graph-travelling algorithm. The speciality is about the packed storage of the lines.

// Outer loop to check all nodes
CheckedNodes = (empty)
for n1 in 1 .. n {
    if (not(CheckedNodes contains n1)) {
        add n1 to CheckedNodes
        VisitedNodes = (empty) // initialization
        VisitableNodes = { n1 } // start the walk from here
        // Inner loop to walk through VisitableNodes
        While (VisitableNodes is not empty) {
            n2 := select one from VisitableNodes
            remove n2 from VisitableNodes
            add n2 to CheckedNodes // this will stop processing again
            for all lines starting from n2 { // we add all points for all lines
                for n3 in line.start .. line.end { 
                    if (VisitedNodes contains n3) { 
                        // we found an already visited node
                        return "Circle found in Graph!" 
                    } else {
                        // otherwise we should visit that later
                        add n3 to VisitableNodes
                    }
                }
             }
        }
    }
}
// we have not found a circle
return "No circle found in Graph!"

The question is the implementation. Here in the algorithm for CheckedNodes and VisitedNodes I use Sets, they - with integer indexes - can be easily implemented by Arrays of Booleans (or something similar). The VisitableNodes is a list, it should rather be implemented by a list-like structure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM