查找有向图中两个顶点之间是否存在路径
给定一个有向图和其中的两个顶点,检查是否存在从第一个给定顶点到第二个给定顶点的路径。
例子:
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 算法:
- 下面的实现是使用 BFS。
- 创建一个队列和一个初始填充为 0 的已访问数组,大小为 V,其中 V 是顶点数。
- 将起始节点插入队列,即将u推入队列,并将u标记为已访问。
- 运行一个循环,直到队列不为空。
- 将队列的前面元素出列。迭代其所有相邻元素。如果任何相邻元素是目标,则返回 true。推送队列中所有相邻和未访问的顶点,并将它们标记为已访问。
- 返回 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)。