web-dev-qa-db-de.com

Zyklen in einem ungerichteten Diagramm

Bei einem ungerichteten Graphen G = ( V , E ) mit n Eckpunkten (| V | = n), wie findest du, ob es einen Zyklus in O (n) enthält?

51
Eran Kampf

Ich denke, diese Tiefensuche löst es. Wenn eine unerforschte Kante zu einem zuvor besuchten Knoten führt, enthält das Diagramm einen Zyklus. Diese Bedingung macht es auch zu O (n), da Sie maximal n Kanten untersuchen können, ohne sie auf true zu setzen oder ohne unerforschte Kanten zu belassen.

60
Rafał Dowgird

Ein zusammenhängender, ungerichteter Graph G ohne Zyklen ist ein Baum! Jeder Baum hat genau n - 1 Kanten, also können wir einfach die Kantenliste des Graphen durchlaufen und die Kanten zählen. Wenn wir n - 1 Kanten zählen, geben wir "Ja" zurück, aber wenn wir die n-te Kante erreichen, geben wir "Nein" zurück. Dies benötigt O (n) Zeit, da wir höchstens n Kanten betrachten.

Aber wenn der Graph nicht verbunden ist, müssten wir DFS verwenden. Wir können die Kanten durchqueren und wenn unerforschte Kanten zu dem besuchten Scheitelpunkt führen, hat er einen Zyklus.

14
Ashish Pani

Sie können es mit DFS lösen. Zeitkomplexität: O (n)

Das Wesentliche des Algorithmus ist, dass, wenn eine verbundene Komponente/ein verbundener Graph KEIN ZYKLUS enthält, es immer ein BAUM ist. Siehe hier zum Beweis

Nehmen wir an, der Graph hat keinen Zyklus, d. H. Er ist ein Baum. Und wenn wir uns einen Baum ansehen, dann jede Kante von einem Knoten:

1.Beides reicht bis zu seinem einzigen Elternteil, der eine Ebene darüber liegt.

2.oder erreicht seine Kinder, die sich eine Ebene darunter befinden.

Wenn also ein Knoten eine andere Kante hat, die nicht zu den beiden oben beschriebenen gehört, verbindet er den Knoten offensichtlich mit einem seiner Vorfahren, der nicht der übergeordnete ist. Dies wird einen ZYKLUS bilden.

Jetzt, da die Fakten klar sind, müssen Sie nur noch eine DFS für das Diagramm ausführen (vorausgesetzt, Ihr Diagramm ist verbunden, ansonsten für alle nicht besuchten Eckpunkte) und WENN Sie einen Nachbarn des Knotens finden, der BESUCHT ist und NICHT dessen ist Elternteil, dann mein Freund gibt es einen ZYKLUS in der Grafik, und Sie sind fertig.

Sie können das übergeordnete Element verfolgen, indem Sie das übergeordnete Element einfach als Parameter übergeben, wenn Sie DFS für seine Nachbarn ausführen. Und da Sie höchstens n Kanten untersuchen müssen, beträgt die Zeitkomplexität O (n).

Hoffe die Antwort hat geholfen.

12
mb1994

Übrigens, wenn Sie zufällig wissen, dass es verbunden ist, dann ist es einfach ein Baum (also keine Zyklen), wenn und nur wenn |E|=|V|-1. Das ist natürlich keine kleine Menge an Informationen :)

7
David

Die Antwort ist wirklich die Breitensuche (oder Tiefensuche, das ist eigentlich egal). Die Details liegen in der Analyse.

Wie schnell ist der Algorithmus?

Stellen Sie sich zunächst vor, der Graph hat keine Zyklen. Die Anzahl der Kanten ist dann O (V), der Graph ist ein Wald, Ziel erreicht.

Stellen Sie sich nun vor, das Diagramm hat Zyklen und Ihr Suchalgorithmus wird beendet und der Erfolg wird im ersten von ihnen gemeldet. Das Diagramm ist ungerichtet. Wenn der Algorithmus eine Kante untersucht, gibt es daher nur zwei Möglichkeiten: Entweder hat er das andere Ende der Kante besucht, oder er hat und dann schließt diese Kante einen Kreis. Sobald der andere Scheitelpunkt der Kante erkannt wird, wird dieser Scheitelpunkt "inspiziert", sodass nur O(V) dieser Operationen vorhanden sind. Der zweite Fall wird während des gesamten Laufs nur einmal erreicht des Algorithmus.

3
jpalecek

Ein einfaches DFS prüft, ob der gegebene ungerichtete Graph einen Zyklus hat oder nicht.

Hier ist der gleichnamige C++ - Code.

Die im obigen Code verwendete Idee lautet:

Wenn ein Knoten, der bereits entdeckt/besucht wurde, erneut gefunden wird und nicht der übergeordnete Knoten ist, haben wir einen Zyklus.

Dies kann auch wie folgt erklärt werden (von @ Rafał Dowgird erwähnt)

Wenn eine unerforschte Kante zu einem zuvor besuchten Knoten führt, enthält das Diagramm einen Zyklus.

1
Chandan Mittal

Sie können Boost-Graph-Bibliothek und zyklische Abhängigkeiten verwenden. Es hat die Lösung zum Finden von Zyklen mit back_Edge Funktion.

1
Bruce

Ein ungerichteter Graph ist azyklisch (d. H. Eine Gesamtstruktur), wenn eine DFS keine hinteren Kanten ergibt. Da die hinteren Kanten die Kanten (u, v) sind, die einen Scheitelpunkt u mit einem Vorfahren v in einem Baum mit der Tiefe zuerst verbinden, gibt es keine hinteren Kanten bedeutet, dass es nur Baumränder gibt, es also keinen Zyklus gibt. So können wir einfach DFS ausführen. Wenn Sie eine Hinterkante finden, gibt es einen Zyklus. Die Komplexität ist O(V) anstelle von O(E + V). Da es eine hintere Kante gibt, muss diese gefunden werden, bevor |V| Verschiedene Kanten angezeigt werden. Dies liegt daran, dass in einer azyklischen (ungerichteten) Gesamtstruktur |E| ≤ |V| + 1.

1
noob_dev

Ich glaube, dass die Annahme, dass der Graph verbunden ist, eine Handvoll sein kann. Somit können Sie den oben gezeigten Beweis verwenden, dass die Laufzeit O (| V |) ist. wenn nicht, dann | E |> | V |. Erinnerung: Die Laufzeit von DFS ist O (| V | + | E |).

1
gor

Ich habe kürzlich angefangen, Graphen zu studieren. Ich habe einen Code in Java) geschrieben, der bestimmen kann, ob ein Diagramm Zyklen enthält. Ich habe DFT verwendet, um Zyklen im Diagramm zu finden. Anstelle einer Rekursion habe ich einen Stapel zum Durchlaufen des Diagramms verwendet.

Auf einer hohen Ebene wird die DFT unter Verwendung eines Stapels in den folgenden Schritten ausgeführt

  1. Besuche einen Knoten
  2. Befindet sich der Knoten nicht in der Liste der besuchten Knoten, fügen Sie ihn der Liste hinzu und verschieben Sie ihn in den oberen Bereich des Stapels
  3. Markieren Sie den Knoten oben im Stapel als aktuellen Knoten.
  4. Wiederholen Sie die obigen Schritte für jeden benachbarten Knoten des aktuellen Knotens
  5. Wenn alle Knoten besucht wurden, wird der aktuelle Knoten vom Stapel genommen

Ich führte eine DFT von jedem Knoten des Graphen aus und überprüfte während des Durchlaufs, ob der Scheitelpunkt eine Stapeltiefe größer als eins hatte, wenn ich auf einen Scheitelpunkt stieß, den ich zuvor besuchte. Ich habe auch geprüft, ob ein Knoten eine Kante für sich hat und ob es mehrere Kanten zwischen Knoten gibt. Die Stack-Version, die ich ursprünglich geschrieben habe, war nicht sehr elegant. Ich habe den Pseudocode gelesen, wie es mit Rekursion gemacht werden kann, und er war ordentlich. Hier ist eine Implementierung von Java. Das LinkedList-Array stellt ein Diagramm dar. Dabei werden jeder Knoten und seine benachbarten Scheitelpunkte durch den Index des Arrays bzw. jedes Elements angegeben

class GFG {
Boolean isCyclic(int V, LinkedList<Integer>[] alist) {
    List<Integer> visited = new ArrayList<Integer>();
    for (int i = 0; i < V; i++) {
        if (!visited.contains(i)) {
            if (isCyclic(i, alist, visited, -1))
                return true;
        }
    }
    return false;
}

Boolean isCyclic(int vertex, LinkedList<Integer>[] alist, List<Integer> visited, int parent) {
    visited.add(vertex);
    for (Iterator<Integer> iterator = alist[vertex].iterator(); iterator.hasNext();) {
        int element = iterator.next();
        if (!visited.contains(element)) {
            if (isCyclic(element, alist, visited, vertex))
                return true;
        } else if (element != parent)
            return true;
    }
    return false;
}

}

1
lalatnayak

Hier ist der Code, den ich in C basierend auf DFS geschrieben habe, um herauszufinden, ob ein gegebener Graph verbunden/zyklisch ist oder nicht. mit einigen Beispielausgaben am Ende. Hoffe es wird hilfreich sein :)

#include<stdio.h>
#include<stdlib.h>

/****Global Variables****/
int A[20][20],visited[20],v=0,count=0,n;
int seq[20],s=0,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);

    }

/ * Beispielausgabe:

[email protected]:~/Desktop$ gcc BFS.c

[email protected]:~/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!


[email protected]:~/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!


[email protected]:~/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!

*/
1
Majid NK

Wie schon andere erwähnt haben ... Eine gründliche erste Suche wird es lösen. In der Regel dauert die erste Suche O (V + E), aber in diesem Fall wissen Sie, dass das Diagramm höchstens O(V) Kanten hat. Sie können also einfach ein DFS ausführen und sobald Sie ein sehen new Edge erhöht einen Zähler. Wenn der Zähler V erreicht hat, müssen Sie nicht fortfahren, da der Graph mit Sicherheit einen Zyklus hat. Offensichtlich dauert dies O (v).

0
HsnVahedi

Ich glaube, dass die korrekte Verwendung von DFS auch davon abhängt, wie Sie Ihr Diagramm im Code darstellen. Angenommen, Sie verwenden benachbarte Listen, um die Nachbarknoten zu verfolgen, und Ihr Diagramm hat zwei Eckpunkte und nur eine Kante: V = {1,2} und E = {(1,2)}. In diesem Fall markiert DFS ab Scheitelpunkt 1 diesen als BESUCHT und stellt 2 in die Warteschlange. Danach wird der Scheitelpunkt 2 entfernt, und da 1 neben 2 liegt und 1 BESUCHT ist, wird die DFS zu dem Schluss kommen, dass ein Zyklus vorliegt (der falsch ist). Mit anderen Worten, in ungerichteten Diagrammen (1,2) und (2,1) handelt es sich um dieselbe Kante, und Sie sollten so codieren, dass DFS sie nicht als unterschiedliche Kanten betrachtet. Das Beibehalten des übergeordneten Knotens für jeden besuchten Knoten trägt zur Behebung dieser Situation bei.

0
TreeStar