📜  检查一个图是否强连接 | Set 1(使用 DFS 的 Kosaraju)

📅  最后修改于: 2022-05-13 01:57:54.039000             🧑  作者: Mango

检查一个图是否强连接 | Set 1(使用 DFS 的 Kosaraju)

给定一个有向图,找出该图是否是强连通的。如果任意两对顶点之间存在路径,则有向图是强连通的。例如,下面是一个强连通图。

连接性3

无向图很容易,我们可以从任意顶点开始做 BFS 和 DFS。如果 BFS 或 DFS 访问所有顶点,则给定的无向图是连通的。这种方法不适用于有向图。例如,考虑以下非强连接图。如果我们从顶点 0 开始 DFS(或 BFS),我们可以到达所有顶点,但如果我们从任何其他顶点开始,我们无法到达所有顶点。

连通性1

有向图怎么办?

一个简单的想法是使用像Floyd Warshall这样的全对最短路径算法或找到图的传递闭包。该方法的时间复杂度为 O(v 3 )。
我们也可以从每个顶点开始DFS V 次。如果任何 DFS 没有访问所有顶点,则图不是强连接的。该算法需要 O(V*(V+E)) 时间,这与密集图的传递闭包相同。
一个更好的主意可以是强连通分量 (SCC)算法。我们可以在 O(V+E) 时间内找到所有 SCC。如果 SCC 的数量为 1,则图是强连接的。 SCC 的算法在找到所有 SCC 时会做额外的工作。
以下是Kosaraju 的基于 DFS 的简单算法,它对图进行两次 DFS 遍历
1)将所有顶点初始化为未访问。
2)从任意顶点v开始对图进行DFS遍历。如果DFS遍历没有访问所有顶点,则返回false。
3)反转所有弧(或找到图的转置或反转)
4)在反向图中将所有顶点标记为未访问。
5)从相同的顶点v开始对反向图进行DFS遍历(与步骤2相同)。如果 DFS 遍历没有访问所有顶点,则返回 false。否则返回真。
这个想法是,如果每个节点都可以从顶点 v 到达,并且每个节点都可以到达 v,那么图是强连接的。在步骤 2 中,我们检查是否所有顶点都可以从 v 到达。在步骤 4 中,我们检查是否所有顶点都可以到达 v(在反转图中,如果所有顶点都可以从 v 到达,那么所有顶点都可以到达原始图中的 v)。
以下是上述算法的实现。

C++
// C++ program to check if a given directed graph is strongly
// connected or not
#include 
#include 
#include 
using namespace std;
 
class Graph
{
    int V;    // No. of vertices
    list *adj;    // An array of adjacency lists
 
    // A recursive function to print DFS starting from v
    void DFSUtil(int v, bool visited[]);
public:
    // Constructor and Destructor
    Graph(int V) { this->V = V;  adj = new list[V];}
    ~Graph() { delete [] adj; }
 
    // Method to add an edge
    void addEdge(int v, int w);
 
    // The main function that returns true if the graph is strongly
    // connected, otherwise false
    bool isSC();
 
    // Function that returns reverse (or transpose) of this graph
    Graph getTranspose();
};
 
// A recursive function to print DFS starting from v
void Graph::DFSUtil(int v, bool visited[])
{
    // Mark the current node as visited and print it
    visited[v] = true;
 
    // Recur for all the vertices adjacent to this vertex
    list::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
        if (!visited[*i])
            DFSUtil(*i, visited);
}
 
// Function that returns reverse (or transpose) of this graph
Graph Graph::getTranspose()
{
    Graph g(V);
    for (int v = 0; v < V; v++)
    {
        // Recur for all the vertices adjacent to this vertex
        list::iterator i;
        for(i = adj[v].begin(); i != adj[v].end(); ++i)
        {
            g.adj[*i].push_back(v);
        }
    }
    return g;
}
 
void Graph::addEdge(int v, int w)
{
    adj[v].push_back(w); // Add w to v’s list.
}
 
// The main function that returns true if graph is strongly connected
bool Graph::isSC()
{
    // St1p 1: Mark all the vertices as not visited (For first DFS)
    bool visited[V];
    for (int i = 0; i < V; i++)
        visited[i] = false;
 
    // Step 2: Do DFS traversal starting from first vertex.
    DFSUtil(0, visited);
 
     // If DFS traversal doesn’t visit all vertices, then return false.
    for (int i = 0; i < V; i++)
        if (visited[i] == false)
             return false;
 
    // Step 3: Create a reversed graph
    Graph gr = getTranspose();
 
    // Step 4: Mark all the vertices as not visited (For second DFS)
    for(int i = 0; i < V; i++)
        visited[i] = false;
 
    // Step 5: Do DFS for reversed graph starting from first vertex.
    // Starting Vertex must be same starting point of first DFS
    gr.DFSUtil(0, visited);
 
    // If all vertices are not visited in second DFS, then
    // return false
    for (int i = 0; i < V; i++)
        if (visited[i] == false)
             return false;
 
    return true;
}
 
// Driver program to test above functions
int main()
{
    // Create graphs given in the above diagrams
    Graph g1(5);
    g1.addEdge(0, 1);
    g1.addEdge(1, 2);
    g1.addEdge(2, 3);
    g1.addEdge(3, 0);
    g1.addEdge(2, 4);
    g1.addEdge(4, 2);
    g1.isSC()? cout << "Yes\n" : cout << "No\n";
 
    Graph g2(4);
    g2.addEdge(0, 1);
    g2.addEdge(1, 2);
    g2.addEdge(2, 3);
    g2.isSC()? cout << "Yes\n" : cout << "No\n";
 
    return 0;
}


Java
// Java program to check if a given directed graph is strongly
// connected or not
import java.io.*;
import java.util.*;
import java.util.LinkedList;
 
// This class represents a directed graph using adjacency
// list representation
class Graph
{
    private int V;   // No. of vertices
    private LinkedList adj[]; //Adjacency List
 
    //Constructor
    Graph(int v)
    {
        V = v;
        adj = new LinkedList[v];
        for (int i=0; i i = adj[v].iterator();
        while (i.hasNext())
        {
            n = i.next();
            if (!visited[n])
                DFSUtil(n,visited);
        }
    }
 
    // Function that returns transpose of this graph
    Graph getTranspose()
    {
        Graph g = new Graph(V);
        for (int v = 0; v < V; v++)
        {
            // Recur for all the vertices adjacent to this vertex
            Iterator i = adj[v].listIterator();
            while (i.hasNext())
                g.adj[i.next()].add(v);
        }
        return g;
    }
 
    // The main function that returns true if graph is strongly
    // connected
    Boolean isSC()
    {
        // Step 1: Mark all the vertices as not visited
        // (For first DFS)
        Boolean visited[] = new Boolean[V];
        for (int i = 0; i < V; i++)
            visited[i] = false;
 
        // Step 2: Do DFS traversal starting from first vertex.
        DFSUtil(0, visited);
 
        // If DFS traversal doesn't visit all vertices, then
        // return false.
        for (int i = 0; i < V; i++)
            if (visited[i] == false)
                return false;
 
        // Step 3: Create a reversed graph
        Graph gr = getTranspose();
 
        // Step 4: Mark all the vertices as not visited (For
        // second DFS)
        for (int i = 0; i < V; i++)
            visited[i] = false;
 
        // Step 5: Do DFS for reversed graph starting from
        // first vertex. Starting Vertex must be same starting
        // point of first DFS
        gr.DFSUtil(0, visited);
 
        // If all vertices are not visited in second DFS, then
        // return false
        for (int i = 0; i < V; i++)
            if (visited[i] == false)
                return false;
 
        return true;
    }
 
    public static void main(String args[])
    {
        // Create graphs given in the above diagrams
        Graph g1 = new Graph(5);
        g1.addEdge(0, 1);
        g1.addEdge(1, 2);
        g1.addEdge(2, 3);
        g1.addEdge(3, 0);
        g1.addEdge(2, 4);
        g1.addEdge(4, 2);
        if (g1.isSC())
            System.out.println("Yes");
        else
            System.out.println("No");
 
        Graph g2 = new Graph(4);
        g2.addEdge(0, 1);
        g2.addEdge(1, 2);
        g2.addEdge(2, 3);
        if (g2.isSC())
            System.out.println("Yes");
        else
            System.out.println("No");
    }
}
// This code is contributed by Aakash Hasija


Python3
# Python program to check if a given directed graph is strongly
# connected or not
 
from collections import defaultdict
 
# This class represents a directed graph using adjacency list representation
 
 
class Graph:
 
    def __init__(self, vertices):
        self.V = vertices  # No. of vertices
        self.graph = defaultdict(list)  # default dictionary to store graph
 
    # function to add an edge to graph
    def addEdge(self, u, v):
        self.graph[u].append(v)
 
     # A function used by isSC() to perform DFS
    def DFSUtil(self, v, visited):
 
        # Mark the current node as visited
        visited[v] = True
 
        # Recur for all the vertices adjacent to this vertex
        for i in self.graph[v]:
            if visited[i] == False:
                self.DFSUtil(i, visited)
 
    # Function that returns reverse (or transpose) of this graph
 
    def getTranspose(self):
 
        g = Graph(self.V)
 
        # Recur for all the vertices adjacent to this vertex
        for i in self.graph:
            for j in self.graph[i]:
                g.addEdge(j, i)
 
        return g
 
    # The main function that returns true if graph is strongly connected
    def isSC(self):
 
         # Step 1: Mark all the vertices as not visited (For first DFS)
        visited =[False]*(self.V)
         
        # Step 2: Do DFS traversal starting from first vertex.
        self.DFSUtil(0,visited)
 
        # If DFS traversal doesnt visit all vertices, then return false
        if any(i == False for i in visited):
            return False
 
        # Step 3: Create a reversed graph
        gr = self.getTranspose()
         
        # Step 4: Mark all the vertices as not visited (For second DFS)
        visited =[False]*(self.V)
 
        # Step 5: Do DFS for reversed graph starting from first vertex.
        # Starting Vertex must be same starting point of first DFS
        gr.DFSUtil(0,visited)
 
        # If all vertices are not visited in second DFS, then
        # return false
        if any(i == False for i in visited):
            return False
 
        return True
 
# Create a graph given in the above diagram
g1 = Graph(5)
g1.addEdge(0, 1)
g1.addEdge(1, 2)
g1.addEdge(2, 3)
g1.addEdge(3, 0)
g1.addEdge(2, 4)
g1.addEdge(4, 2)
print ("Yes" if g1.isSC() else "No")
 
g2 = Graph(4)
g2.addEdge(0, 1)
g2.addEdge(1, 2)
g2.addEdge(2, 3)
print ("Yes" if g2.isSC() else "No")
 
# This code is contributed by Neelam Yadav


Javascript


输出:

Yes
No