📌  相关文章
📜  查找有向图中两个顶点之间是否存在路径

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

查找有向图中两个顶点之间是否存在路径

给定一个有向图和其中的两个顶点,检查是否存在从第一个给定顶点到第二个给定顶点的路径。
例子:

Consider the following Graph:


Input : (u, v) = (1, 3)
Output: Yes
Explanation: There is a path from 1 to 3, 1 -> 2 -> 3

Input : (u, v) = (3, 6)
Output: No
Explanation: There is no path from 3 to 6

方法:可以使用广度优先搜索 (BFS) 或深度优先搜索 (DFS) 来查找两个顶点之间的路径。以BFS(或DFS)中的第一个顶点为源,遵循标准的BFS(或DFS)。如果在我们的遍历中找到第二个顶点,则返回 true,否则返回 false。

BFS 算法:

  1. 下面的实现是使用 BFS。
  2. 创建一个队列和一个初始填充为 0 的已访问数组,大小为 V,其中 V 是顶点数。
  3. 将起始节点插入队列,即将u推入队列,并将u标记为已访问。
  4. 运行一个循环,直到队列不为空。
  5. 将队列的前面元素出列。迭代其所有相邻元素。如果任何相邻元素是目标,则返回 true。推送队列中所有相邻和未访问的顶点,并将它们标记为已访问。
  6. 返回 false,因为在 BFS 中没有到达目的地。

实现: C++、 Java和Python代码使用 BFS 从第一个顶点查找第二个顶点的可达性。

C++
// C++ program to check if there is exist a path between two vertices
// of a graph.
#include
#include 
using namespace std;
 
// This class represents a directed graph using adjacency list
// representation
class Graph
{
    int V;    // No. of vertices
    list *adj;    // Pointer to an array containing adjacency lists
public:
    Graph(int V);  // Constructor
    void addEdge(int v, int w); // function to add an edge to graph
    bool isReachable(int s, int d); 
};
 
Graph::Graph(int V)
{
    this->V = V;
    adj = new list[V];
}
 
void Graph::addEdge(int v, int w)
{
    adj[v].push_back(w); // Add w to v’s list.
}
 
// A BFS based function to check whether d is reachable from s.
bool Graph::isReachable(int s, int d)
{
    // Base case
    if (s == d)
      return true;
 
    // Mark all the vertices as not visited
    bool *visited = new bool[V];
    for (int i = 0; i < V; i++)
        visited[i] = false;
 
    // Create a queue for BFS
    list queue;
 
    // Mark the current node as visited and enqueue it
    visited[s] = true;
    queue.push_back(s);
 
    // it will be used to get all adjacent vertices of a vertex
    list::iterator i;
 
    while (!queue.empty())
    {
        // Dequeue a vertex from queue and print it
        s = queue.front();
        queue.pop_front();
 
        // Get all adjacent vertices of the dequeued vertex s
        // If a adjacent has not been visited, then mark it visited
        // and enqueue it
        for (i = adj[s].begin(); i != adj[s].end(); ++i)
        {
            // If this adjacent node is the destination node, then
            // return true
            if (*i == d)
                return true;
 
            // Else, continue to do BFS
            if (!visited[*i])
            {
                visited[*i] = true;
                queue.push_back(*i);
            }
        }
    }
     
    // If BFS is complete without visiting d
    return false;
}
 
// Driver program to test methods of graph class
int main()
{
    // Create a graph given in the above diagram
    Graph g(4);
    g.addEdge(0, 1);
    g.addEdge(0, 2);
    g.addEdge(1, 2);
    g.addEdge(2, 0);
    g.addEdge(2, 3);
    g.addEdge(3, 3);
 
    int u = 1, v = 3;
    if(g.isReachable(u, v))
        cout<< "\n There is a path from " << u << " to " << v;
    else
        cout<< "\n There is no path from " << u << " to " << v;
 
    u = 3, v = 1;
    if(g.isReachable(u, v))
        cout<< "\n There is a path from " << u << " to " << v;
    else
        cout<< "\n There is no path from " << u << " to " << v;
 
    return 0;
}


Java
// Java program to check if there is exist a path between two vertices
// of a graph.
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; itemp;
 
        // Mark all the vertices as not visited(By default set
        // as false)
        boolean visited[] = new boolean[V];
 
        // Create a queue for BFS
        LinkedList queue = new LinkedList();
 
        // Mark the current node as visited and enqueue it
        visited[s]=true;
        queue.add(s);
 
        // 'i' will be used to get all adjacent vertices of a vertex
        Iterator i;
        while (queue.size()!=0)
        {
            // Dequeue a vertex from queue and print it
            s = queue.poll();
 
            int n;
            i = adj[s].listIterator();
 
            // Get all adjacent vertices of the dequeued vertex s
            // If a adjacent has not been visited, then mark it
            // visited and enqueue it
            while (i.hasNext())
            {
                n = i.next();
 
                // If this adjacent node is the destination node,
                // then return true
                if (n==d)
                    return true;
 
                // Else, continue to do BFS
                if (!visited[n])
                {
                    visited[n] = true;
                    queue.add(n);
                }
            }
        }
 
        // If BFS is complete without visited d
        return false;
    }
 
    // Driver method
    public static void main(String args[])
    {
        // Create a graph given in the above diagram
        Graph g = new Graph(4);
        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(1, 2);
        g.addEdge(2, 0);
        g.addEdge(2, 3);
        g.addEdge(3, 3);
 
        int u = 1;
        int v = 3;
        if (g.isReachable(u, v))
            System.out.println("There is a path from " + u +" to " + v);
        else
            System.out.println("There is no path from " + u +" to " + v);;
 
        u = 3;
        v = 1;
        if (g.isReachable(u, v))
            System.out.println("There is a path from " + u +" to " + v);
        else
            System.out.println("There is no path from " + u +" to " + v);;
    }
}
// This code is contributed by Aakash Hasija


Python3
# program to check if there is exist a path between two vertices
# of a graph
 
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)
      
     # Use BFS to check path between s and d
    def isReachable(self, s, d):
        # Mark all the vertices as not visited
        visited =[False]*(self.V)
  
        # Create a queue for BFS
        queue=[]
  
        # Mark the source node as visited and enqueue it
        queue.append(s)
        visited[s] = True
  
        while queue:
 
            #Dequeue a vertex from queue
            n = queue.pop(0)
             
            # If this adjacent node is the destination node,
            # then return true
            if n == d:
                   return True
 
            #  Else, continue to do BFS
            for i in self.graph[n]:
                if visited[i] == False:
                    queue.append(i)
                    visited[i] = True
         # If BFS is complete without visited d
        return False
  
# Create a graph given in the above diagram
g = Graph(4)
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(1, 2)
g.addEdge(2, 0)
g.addEdge(2, 3)
g.addEdge(3, 3)
 
u =1; v = 3
 
if g.isReachable(u, v):
    print("There is a path from %d to %d" % (u,v))
else :
    print("There is no path from %d to %d" % (u,v))
 
u = 3; v = 1
if g.isReachable(u, v) :
    print("There is a path from %d to %d" % (u,v))
else :
    print("There is no path from %d to %d" % (u,v))
 
#This code is contributed by Neelam Yadav


C#
// C# program to check if there is
// exist a path between two vertices
// of a graph.
using System;
using System.Collections;
using System.Collections.Generic;
 
// 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 < v; ++i)
      adj[i] = new LinkedList();
  }
 
  // Function to add an edge into the graph
  void addEdge(int v, int w)
  {
    adj[v].AddLast(w);
  }
 
  // prints BFS traversal from a given source s
  bool isReachable(int s, int d)
  {
    // LinkedList temp = new LinkedList();
 
    // Mark all the vertices as not visited(By default set
    // as false)
    bool[] visited = new bool[V];
 
    // Create a queue for BFS
    LinkedList queue = new LinkedList();
 
    // Mark the current node as visited and enqueue it
    visited[s] = true;
    queue.AddLast(s);
 
    // 'i' will be used to get all adjacent vertices of a vertex
    IEnumerator i;     
    while (queue.Count != 0)
    {
 
      // Dequeue a vertex from queue and print it
      s = queue.First.Value;
      queue.RemoveFirst();
      int n;
      i = adj[s].GetEnumerator();
 
      // Get all adjacent vertices of the dequeued vertex s
      // If a adjacent has not been visited, then mark it
      // visited and enqueue it
      while (i.MoveNext())
      {
        n = (int)i.Current;
 
        // If this adjacent node is the destination node,
        // then return true
        if (n == d)
          return true;
 
        // Else, continue to do BFS
        if (!visited[n])
        {
          visited[n] = true;
          queue.AddLast(n);
        }
      }
    }
 
    // If BFS is complete without visited d
    return false;
  }
 
  // Driver method
  public static void Main(string[] args)
  {
 
    // Create a graph given in the above diagram
    Graph g = new Graph(4);
    g.addEdge(0, 1);
    g.addEdge(0, 2);
    g.addEdge(1, 2);
    g.addEdge(2, 0);
    g.addEdge(2, 3);
    g.addEdge(3, 3);
    int u = 1;
    int v = 3;
    if (g.isReachable(u, v))
      Console.WriteLine("There is a path from " + u + " to " + v);
    else
      Console.WriteLine("There is no path from " + u + " to " + v);
    u = 3;
    v = 1;
    if (g.isReachable(u, v))
      Console.WriteLine("There is a path from " + u + " to " + v);
    else
      Console.WriteLine("There is no path from " + u + " to " + v);
  }
}
 
// This code is contributed by sanjeev2552


Javascript


C++14
#include 
using namespace std;
typedef long long ll;
 
vector adj[100000];
bool visited[100000];
 
bool dfs(int start, int end)
{
    if (start == end)
        return true;
    visited[start] = 1;
    for (auto x : adj[start]) {
        if (!visited[x])
            if (dfs(x, end))
                return true;
    }
    return false;
}
 
int main()
{
 
    int V = 4;
    vector members = { 2, 5, 7, 9 };
 
    int E = 4;
    vector > connections
        = { { 2, 9 }, { 7, 2 }, { 7, 9 }, { 9, 5 } };
 
    for (int i = 0; i < E; i++)
        adj[connections[i].first].push_back(
            connections[i].second);
 
    int sender = 7, receiver = 9;
 
    if (dfs(sender, receiver))
        cout << "1";
    else
        cout << "0";
 
    return 0;
}
// this code is contributed by prophet1999


输出
There is a path from 1 to 3
 There is no path from 3 to 1

复杂性分析:

  • 时间复杂度: O(V+E),其中 V 是图中的顶点数,E 是图中的边数。
  • 空间复杂度: O(V)。
    队列中最多可以有 V 个元素。所以需要的空间是O(V)。

DFS 算法:

1. 如果start==end返回1 ,因为我们必须到达目的地。

2. 将开始标记为已访问

3.遍历start的直接连接的顶点,并为每个这样的未探索顶点递归函数dfs

4. 如果我们没有到达目的地,则返回0

执行:

C++14

#include 
using namespace std;
typedef long long ll;
 
vector adj[100000];
bool visited[100000];
 
bool dfs(int start, int end)
{
    if (start == end)
        return true;
    visited[start] = 1;
    for (auto x : adj[start]) {
        if (!visited[x])
            if (dfs(x, end))
                return true;
    }
    return false;
}
 
int main()
{
 
    int V = 4;
    vector members = { 2, 5, 7, 9 };
 
    int E = 4;
    vector > connections
        = { { 2, 9 }, { 7, 2 }, { 7, 9 }, { 9, 5 } };
 
    for (int i = 0; i < E; i++)
        adj[connections[i].first].push_back(
            connections[i].second);
 
    int sender = 7, receiver = 9;
 
    if (dfs(sender, receiver))
        cout << "1";
    else
        cout << "0";
 
    return 0;
}
// this code is contributed by prophet1999
输出
1

复杂性分析:

时间复杂度: O(V+E),其中V是图中的顶点数, E是图中的边数。
空间复杂度: O(V)。
堆栈中最多可以有V个元素。所以需要的空间是O(V)。