括号定理用于图的DFS中。它指出深度优先搜索树中的后代具有有趣的属性。如果v是u的后代,则v的发现时间晚于u的发现时间。
在图g =(V,E)的任何DFS遍历中,对于任意两个顶点u和v,以下任一正好成立:
- 间隔[d [u],f [u]]和[d [v],f [v]]完全不相交,并且u和v都不是深度优先林中另一个的后代。
- 间隔[d [u],f [u]]包含在间隔[d [v],f [v]]内,并且u是深度优先树中v的后代。
- 间隔[d [v],f [v]]完全包含在间隔[d [u],f [u]]中,并且v是深度优先树中u的后代。
边缘分类:
DFS遍历可用于对输入图G =(V,E)的边缘进行分类。可以根据深度优先林定义四种边缘类型:
- 树边缘:这是在图上应用DFS后获得的树中存在的边缘。
- 前向边缘:它是一个边缘(u,v),使得v是后代,但不是DFS树的一部分。
- 后边缘:这是一条边缘(u,v),因此v是边缘u的祖先,但不是DFS树的一部分。后边缘的存在指示有向图中的循环。
- 交叉边缘:这是连接两个节点的一条边缘,这样它们之间就没有任何祖先和后代关系。
给定一个由N个顶点和M个边缘组成的图形,任务是将M个边缘分类为“树”边缘,“前”边缘,“后”边缘和“交叉”边缘。
例子:
Input: N = 5, M = 7, arr[][] = { { 1, 2 }, { 1, 3 }, { 3, 4 }, { 1, 4 }, { 2, 5 }, { 5, 1 }, { 3, 2 } } }
Output:
{1, 2} -> Tree Edge
{1, 3} -> Tree Edge
{3, 4} -> Tree Edge
{1, 4} -> Forward Edge
{2, 5} -> Tree Edge
{5, 1} -> Backward Edge
{3, 2} -> Cross Edge
Explanation:
1. Green Edges: Tree Edge
2. Blue Edges: Forward Edge
3. Black Edges: Backward Edge
4. Red Edges: Cross Edge
Below is the given graph for the above information:
Input: N = 5, M = 4, arr[][] = { { 1, 2 }, { 1, 3 }, { 3, 4 }, { 1, 4 } }
Output:
{1, 2} -> Tree Edge
{1, 3} -> Tree Edge
{3, 4} -> Tree Edge
{1, 4} -> Forward Edge
Explanation:
1. Green Edges: Tree Edge
2. Blue Edges: Forward Edge
3. Black Edges: Backward Edge
4. Red Edges: Cross Edge
Below is the given graph for the above information:
方法:
- 在给定的图形上使用DFS遍历,以发现发现时间和完成时间以及每个节点的父级。
- 通过使用括号定理,可以在以下条件下对给定边进行分类:
- 树边缘:对于任何(U,V)边缘,如果节点U是节点V的父节点,则(U,V)是给定图的树边缘。
- 前向边缘:对于任何边缘(U,V) ,如果节点V的发现时间和完成时间与节点U的发现时间和完成时间完全重叠,则(U,V)是给定图的前向边缘。
- Backward Edge:对于任何Edge (U,V) ,如果节点U的发现时间和完成时间与节点V的发现时间和完成时间完全重叠,则(U,V)是给定图的Backward Edge。
- 交叉边缘:对于任何边缘(U,V) ,如果节点U的发现时间和完成时间与节点V的发现时间和完成时间不重叠,则(U,V)是给定图的交叉边缘。
下面是上述方法的实现:
CPP
// C++ program for the above approach
#include "bits/stdc++.h"
using namespace std;
// For recording time
int tim = 0;
// For creating Graph
vector > G;
// For calculating Discovery time
// and finishing time of nodes
vector disc, fin;
// For finding Parent of node
vector Par;
// For storing color of node
vector Color;
// Recursive function for DFS
// to update the
void DFS_Visit(int v)
{
// Make the current nodes as visited
Color[v] = 'G';
// Increment the time
tim = tim + 1;
// Assign the Discovery node of
// node v
disc[v] = tim;
// Traverse the adjacency list of
// vertex v
for (auto& it : G[v]) {
// If the nodes is not visited,
// then mark the parent of the
// current node and call DFS_Visit
// for the current node
if (Color[it] == 'W') {
Par[it] = v;
DFS_Visit(it);
}
}
Color[v] = 'B';
tim = tim + 1;
fin[v] = tim;
}
void DFS(vector >& G)
{
// Intialise Par, disc, fin and
// Color vector to size of graph
Par.resize(G.size());
disc.resize(G.size());
fin.resize(G.size());
Color.resize(G.size());
// Initialise the Par[], Color[],
// disc[], fin[]
for (int i = 1; i < G.size(); i++) {
Color[i] = 'W';
Par[i] = 0;
disc[i] = 0;
fin[i] = 0;
}
// For every vertex if nodes is
// not visited then call DFS_Visit
// to update the discovery and
// finishing time of the node
for (int i = 1; i < G.size(); i++) {
// If color is 'W', then
// node is not visited
if (Color[i] == 'W') {
DFS_Visit(i);
}
}
}
// Function to check whether
// time intervals of x and y overlaps
// or not
bool checkOverlap(int x, int y)
{
// Find the time intervals
int x1 = disc[x], y1 = fin[x];
int x2 = disc[y], y2 = fin[y];
// Complete overlaps
if (x2 > x1 && y1 > y2) {
return true;
}
else {
return false;
}
}
// Function to check which Edges
// (x, y) belongs
string checkEdge(int x, int y)
{
// For Tree Edge
// If x is parent of y, then it
// is Tree Edge
if (Par[y] == x) {
return "Tree Edge";
}
// For Forward Edge
else if (checkOverlap(x, y)) {
return "Forward Edge";
}
// For Backward Edge
else if (checkOverlap(y, x)) {
return "Backward Edge";
}
else {
return "Cross Edge";
}
}
// Function call to find the Tree Edge,
// Back Edge, Forward Edge, and Cross Edge
void solve(int arr[][2], int N, int M)
{
// Create graph of N size
G.resize(N + 1);
// Traverse each edges
for (int i = 0; i < M; i++) {
int x = arr[i][0];
int y = arr[i][1];
// Make Directed graph
G[x].push_back(y);
}
// DFS call to calculate discovery
// and finishing time for each node
DFS(G);
// Condition for Tree Edge, Forward
// Edges, Backward Edge and Cross Edge
for (int i = 0; i < M; i++) {
int x = arr[i][0];
int y = arr[i][1];
// Function call to check Edges
cout << "{" << x << ", " << y
<< "} -> " << checkEdge(x, y)
<< endl;
}
}
// Driver Code
int main()
{
// Number of Nodes
int N = 5;
// Number of Edges
int M = 7;
// Edges for the graph
int arr[M][2]
= { { 1, 2 }, { 1, 3 },
{ 3, 4 }, { 1, 4 },
{ 2, 5 }, { 5, 1 },
{ 3, 1 } };
// Function Call
solve(arr, N, M);
return 0;
}
{1, 2} -> Tree Edge
{1, 3} -> Tree Edge
{3, 4} -> Tree Edge
{1, 4} -> Forward Edge
{2, 5} -> Tree Edge
{5, 1} -> Backward Edge
{3, 1} -> Backward Edge