使用 DFS 的图的传递闭包
给定一个有向图,找出给定图中所有顶点对 (u, v) 的顶点 v 是否可以从另一个顶点 u 到达。这里可达性意味着存在从顶点 u 到 v 的路径。可达性矩阵称为图的传递闭包。
For example, consider below graph
Transitive closure of above graphs is
1 1 1 1
1 1 1 1
1 1 1 1
0 0 0 1
我们在这里讨论了一个 O(V 3 ) 解决方案。该解决方案基于 Floyd Warshall 算法。在这篇文章中,讨论了一个 O(V(V+E)) 算法。因此,对于密集图,它将变为 O(V 3 ),而对于稀疏图,它将变为 O(V 2 )。
下面是算法的抽象步骤。
- 创建一个矩阵 tc[V][V],它最终将具有给定图的传递闭包。将 tc[][] 的所有条目初始化为 0。
- 为图的每个节点调用 DFS 以在 tc[][] 中标记可达顶点。在对 DFS 的递归调用中,如果相邻顶点已在 tc[][] 中标记为可达,我们不会为相邻顶点调用 DFS。
下面是上述思想的实现。该代码使用输入图的邻接表表示并构建矩阵 tc[V][V] 使得如果 v 可以从 u 到达,则 tc[u][v] 为真。
C++
// C++ program to print transitive closure of a graph
#include
using namespace std;
class Graph
{
int V; // No. of vertices
bool **tc; // To store transitive closure
list *adj; // array of adjacency lists
void DFSUtil(int u, int v);
public:
Graph(int V); // Constructor
// function to add an edge to graph
void addEdge(int v, int w) { adj[v].push_back(w); }
// prints transitive closure matrix
void transitiveClosure();
};
Graph::Graph(int V)
{
this->V = V;
adj = new list[V];
tc = new bool* [V];
for (int i = 0; i < V; i++)
{
tc[i] = new bool[V];
memset(tc[i], false, V*sizeof(bool));
}
}
// A recursive DFS traversal function that finds
// all reachable vertices for s.
void Graph::DFSUtil(int s, int v)
{
// Mark reachability from s to t as true.
if(s==v){
if(find(adj[v].begin(),adj[v].end(),v)!=adj[v].end())
tc[s][v] = true;
}
else
tc[s][v] = true;
// Find all the vertices reachable through v
list::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i)
{
if (tc[s][*i] == false)
{
if(*i==s)
{
tc[s][*i]=1;
}
else
{
DFSUtil(s, *i);
}
}
}
}
// The function to find transitive closure. It uses
// recursive DFSUtil()
void Graph::transitiveClosure()
{
// Call the recursive helper function to print DFS
// traversal starting from all vertices one by one
for (int i = 0; i < V; i++)
DFSUtil(i, i); // Every vertex is reachable from self.
for (int i=0; i
Java
// JAVA program to print transitive
// closure of a graph.
import java.util.ArrayList;
import java.util.Arrays;
// A directed graph using
// adjacency list representation
public class Graph {
// No. of vertices in graph
private int vertices;
// adjacency list
private ArrayList[] adjList;
// To store transitive closure
private int[][] tc;
// Constructor
public Graph(int vertices) {
// initialise vertex count
this.vertices = vertices;
this.tc = new int[this.vertices][this.vertices];
// initialise adjacency list
initAdjList();
}
// utility method to initialise adjacency list
@SuppressWarnings("unchecked")
private void initAdjList() {
adjList = new ArrayList[vertices];
for (int i = 0; i < vertices; i++) {
adjList[i] = new ArrayList<>();
}
}
// add edge from u to v
public void addEdge(int u, int v) {
// Add v to u's list.
adjList[u].add(v);
}
// The function to find transitive
// closure. It uses
// recursive DFSUtil()
public void transitiveClosure() {
// Call the recursive helper
// function to print DFS
// traversal starting from all
// vertices one by one
for (int i = 0; i < vertices; i++) {
dfsUtil(i, i);
}
for (int i = 0; i < vertices; i++) {
System.out.println(Arrays.toString(tc[i]));
}
}
// A recursive DFS traversal
// function that finds
// all reachable vertices for s
private void dfsUtil(int s, int v) {
// Mark reachability from
// s to v as true.
if(s==v){
if(adjList[v].contains(v))
tc[s][v] = 1;
}
else
tc[s][v] = 1;
// Find all the vertices reachable
// through v
for (int adj : adjList[v]) {
if (tc[s][adj]==0) {
dfsUtil(s, adj);
}
}
}
// Driver Code
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);
System.out.println("Transitive closure " +
"matrix is");
g.transitiveClosure();
}
}
// This code is contributed
// by Himanshu Shekhar
Python3
# Python program to print transitive
# closure of a graph.
from collections import defaultdict
class Graph:
def __init__(self,vertices):
# No. of vertices
self.V = vertices
# default dictionary to store graph
self.graph = defaultdict(list)
# To store transitive closure
self.tc = [[0 for j in range(self.V)] for i in range(self.V)]
# function to add an edge to graph
def addEdge(self, u, v):
self.graph[u].append(v)
# A recursive DFS traversal function that finds
# all reachable vertices for s
def DFSUtil(self, s, v):
# Mark reachability from s to v as true.
if(s == v):
if( v in self.graph[s]):
self.tc[s][v] = 1
else:
self.tc[s][v] = 1
# Find all the vertices reachable through v
for i in self.graph[v]:
if self.tc[s][i] == 0:
if s==i:
self.tc[s][i]=1
else:
self.DFSUtil(s, i)
# The function to find transitive closure. It uses
# recursive DFSUtil()
def transitiveClosure(self):
# Call the recursive helper function to print DFS
# traversal starting from all vertices one by one
for i in range(self.V):
self.DFSUtil(i, i)
print(self.tc)
# 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)
g.transitiveClosure()
C#
// C# program to print transitive
// closure of a graph.
using System;
using System.Collections.Generic;
// A directed graph using
// adjacency list representation
public class Graph
{
// No. of vertices in graph
private int vertices;
// adjacency list
private List[] adjList;
// To store transitive closure
private int[,] tc;
// Constructor
public Graph(int vertices)
{
// initialise vertex count
this.vertices = vertices;
this.tc = new int[this.vertices, this.vertices];
// initialise adjacency list
initAdjList();
}
// utility method to initialise adjacency list
private void initAdjList()
{
adjList = new List[vertices];
for (int i = 0; i < vertices; i++)
{
adjList[i] = new List();
}
}
// add edge from u to v
public void addEdge(int u, int v)
{
// Add v to u's list.
adjList[u].Add(v);
}
// The function to find transitive
// closure. It uses
// recursive DFSUtil()
public void transitiveClosure() {
// Call the recursive helper
// function to print DFS
// traversal starting from all
// vertices one by one
for (int i = 0; i < vertices; i++) {
dfsUtil(i, i);
}
for (int i = 0; i < vertices; i++) {
for(int j = 0; j < vertices; j++)
Console.Write(tc[i, j] + " ");
Console.WriteLine();
}
}
// A recursive DFS traversal
// function that finds
// all reachable vertices for s
private void dfsUtil(int s, int v) {
// Mark reachability from
// s to v as true.
if(s==v){
if(adjList[v].contains(v))
tc[s][v] = 1;
}
else
tc[s, v] = 1;
// Find all the vertices reachable
// through v
foreach (int adj in adjList[v])
{
if (tc[s, adj] == 0) {
dfsUtil(s, adj);
}
}
}
// Driver Code
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);
Console.WriteLine("Transitive closure " +
"matrix is");
g.transitiveClosure();
}
}
// This code is contributed by Rajput-Ji
输出
Transitive closure matrix is
1 1 1 1
1 1 1 1
1 1 1 1
0 0 0 1
输出:
Transitive closure matrix is
1 1 1 1
1 1 1 1
1 1 1 1
0 0 0 1