Обнаружение циклов на графике с использованием DFS: 2 разных подхода и в чем разница
обратите внимание, что график представлен как список смежности.
Я слышал о 2 подходах, чтобы найти цикл в графике:
храните массив логических значений, чтобы отслеживать, посещали ли вы узел раньше. Если у вас закончились новые узлы для перехода (не задев узел, который вы уже были), просто отследите и попробуйте другую ветку.
один из CLRS Кормена или Skiena: для глубины-первый поиск в неориентированном графики, есть два типа ребер, дерево и обратно. График имеет цикл тогда и только тогда, когда существует задний край.
может кто-нибудь объяснить, что такое задние края графика и в чем разница между вышеуказанными 2 методами.
спасибо.
обновление: Вот код для обнаружения циклов в обоих случаях. Graph-это простой класс, который представляет все узлы графа как уникальные числа для простоты, каждый узел имеет свой смежный соседние узлы (g.getAdjacentNodes (int)):
public class Graph {
private int[][] nodes; // all nodes; e.g. int[][] nodes = {{1,2,3}, {3,2,1,5,6}...};
public int[] getAdjacentNodes(int v) {
return nodes[v];
}
// number of vertices in a graph
public int vSize() {
return nodes.length;
}
}
Java-кода для обнаружения циклов в неориентированном графе:
public class DFSCycle {
private boolean marked[];
private int s;
private Graph g;
private boolean hasCycle;
// s - starting node
public DFSCycle(Graph g, int s) {
this.g = g;
this.s = s;
marked = new boolean[g.vSize()];
findCycle(g,s,s);
}
public boolean hasCycle() {
return hasCycle;
}
public void findCycle(Graph g, int v, int u) {
marked[v] = true;
for (int w : g.getAdjacentNodes(v)) {
if(!marked[w]) {
marked[w] = true;
findCycle(g,w,v);
} else if (v != u) {
hasCycle = true;
return;
}
}
}
}
код Java для обнаружения циклов в направленном графике:
public class DFSDirectedCycle {
private boolean marked[];
private boolean onStack[];
private int s;
private Graph g;
private boolean hasCycle;
public DFSDirectedCycle(Graph g, int s) {
this.s = s
this.g = g;
marked = new boolean[g.vSize()];
onStack = new boolean[g.vSize()];
findCycle(g,s);
}
public boolean hasCycle() {
return hasCycle;
}
public void findCycle(Graph g, int v) {
marked[v] = true;
onStack[v] = true;
for (int w : g.adjacentNodes(v)) {
if(!marked[w]) {
findCycle(g,w);
} else if (onStack[w]) {
hasCycle = true;
return;
}
}
onStack[v] = false;
}
}
3 ответов
отвечая на мой вопрос:
график имеет цикл тогда и только тогда, когда существует задний край. Задний край-это край, который находится от узла к себе (selfloop) или один из его предков в дереве, созданном DFS, образующим цикл.
оба подхода выше фактически означают одно и то же. Однако, этот метод может быть применен только в неориентированных графах.
причина, по которой этот алгоритм не работает для направленных графов, заключается в том, что в направленный граф 2 разных пути к одной и той же вершине не сделать цикл. Например: A->B, B - >C, A - >C-не делайте цикл, тогда как в неориентированных: A-B, B-C, C-A делает.
найти цикл в неориентированных графах
неориентированный граф имеет цикл тогда и только тогда, когда поиск глубины (DFS) находит ребро, которое указывает на уже посещенную вершину (задний край).
найти цикл в направленных графов
In помимо посещенных вершин нам нужно отслеживать вершины, находящиеся в настоящее время в рекурсивном стеке функции для обхода DFS. Если мы достигнем вершины, которая уже находится в стеке рекурсии, то в дереве будет цикл.
обновление: Рабочий код находится в разделе вопросов выше.
для завершения можно найти циклы в направленном графе с помощью DFS (from Википедия):
L ← Empty list that will contain the sorted nodes
while there are unmarked nodes do
select an unmarked node n
visit(n)
function visit(node n)
if n has a temporary mark then stop (not a DAG)
if n is not marked (i.e. has not been visited yet) then
mark n temporarily
for each node m with an edge from n to m do
visit(m)
mark n permanently
unmark n temporarily
add n to head of L
вот код, который я написал на C на основе DFS, чтобы узнать, является ли данный неориентированный граф подключен / циклический или нет. с некоторым выходом образца в конце. Надеюсь, это будет полезно :)
#include<stdio.h>
#include<stdlib.h>
/****Global Variables****/
int A[20][20],visited[20],count=0,n;
int seq[20],connected=1,acyclic=1;
/****DFS Function Declaration****/
void DFS();
/****DFSearch Function Declaration****/
void DFSearch(int cur);
/****Main Function****/
int main()
{
int i,j;
printf("\nEnter no of Vertices: ");
scanf("%d",&n);
printf("\nEnter the Adjacency Matrix(1/0):\n");
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&A[i][j]);
printf("\nThe Depth First Search Traversal:\n");
DFS();
for(i=1;i<=n;i++)
printf("%c,%d\t",'a'+seq[i]-1,i);
if(connected && acyclic) printf("\n\nIt is a Connected, Acyclic Graph!");
if(!connected && acyclic) printf("\n\nIt is a Not-Connected, Acyclic Graph!");
if(connected && !acyclic) printf("\n\nGraph is a Connected, Cyclic Graph!");
if(!connected && !acyclic) printf("\n\nIt is a Not-Connected, Cyclic Graph!");
printf("\n\n");
return 0;
}
/****DFS Function Definition****/
void DFS()
{
int i;
for(i=1;i<=n;i++)
if(!visited[i])
{
if(i>1) connected=0;
DFSearch(i);
}
}
/****DFSearch Function Definition****/
void DFSearch(int cur)
{
int i,j;
visited[cur]=++count;
seq[count]=cur;
for(i=1;i<count-1;i++)
if(A[cur][seq[i]])
acyclic=0;
for(i=1;i<=n;i++)
if(A[cur][i] && !visited[i])
DFSearch(i);
}
Пример Вывода:
majid@majid-K53SC:~/Desktop$ gcc BFS.c
majid@majid-K53SC:~/Desktop$ ./a.out
************************************
Enter no of Vertices: 10
Enter the Adjacency Matrix(1/0):
0 0 1 1 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 1 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 1 0 0 0
The Depdth First Search Traversal:
a,1 c,2 d,3 f,4 b,5 e,6 g,7 h,8 i,9 j,10
It is a Not-Connected, Cyclic Graph!
majid@majid-K53SC:~/Desktop$ ./a.out
************************************
Enter no of Vertices: 4
Enter the Adjacency Matrix(1/0):
0 0 1 1
0 0 1 0
1 1 0 0
0 0 0 1
The Depth First Search Traversal:
a,1 c,2 b,3 d,4
It is a Connected, Acyclic Graph!
majid@majid-K53SC:~/Desktop$ ./a.out
************************************
Enter no of Vertices: 5
Enter the Adjacency Matrix(1/0):
0 0 0 1 0
0 0 0 1 0
0 0 0 0 1
1 1 0 0 0
0 0 1 0 0
The Depth First Search Traversal:
a,1 d,2 b,3 c,4 e,5
It is a Not-Connected, Acyclic Graph!
*/