Comment vérifier si un graphe orienté est acyclique? Et comment s'appelle l'algorithme? J'apprécierais une référence.Comment vérifier si un graphe orienté est acyclique?
Répondre
Je voudrais essayer de sort the graph topologically, et si vous ne pouvez pas, alors il a des cycles.
Comment cela n'a-t-il pas eu de votes ?? C'est linéaire sur les nœuds + bords, bien supérieur aux solutions O (n^2)! –
Je viens de répondre :) – FryGuy
Dans de nombreux cas, un DFS (voir la réponse de J.Conrod) peut être plus facile, surtout si un DFS doit être exécuté de toute façon. Mais bien sûr, cela dépend du contexte. – sleske
La solution donnée par ShuggyCoUk est incomplète, car il pourrait ne pas vérifier tous les nœuds.
def isDAG(nodes V):
while there is an unvisited node v in V:
bool cycleFound = dfs(v)
if cyclefound:
return false
return true
Cela a timecomplexity O (n + m) ou O (n^2)
le mien est en effet incorrect - je l'ai supprimé bien que votre semble maintenant un peu hors contexte – ShuggyCoUk
O (n + m) <= O (n + n) = O (2n), O (2n)! = O (n^2) – Artru
@Artru O (n^2) lors de l'utilisation de la matrice d'adjacence, O (n + m) lors de l'utilisation de la liste d'adjacence pour représenter le graphe. – 0x450
Faire simple profondeur la première recherche est pas assez bon pour trouver un cycle. Il est possible de visiter un nœud plusieurs fois dans un DFS sans qu'un cycle existe. Selon l'endroit où vous commencez, vous pourriez également ne pas visiter le graphique entier.
Vous pouvez vérifier les cycles d'un composant connecté d'un graphique comme suit. Trouver un nœud qui n'a que des bords sortants. S'il n'y a pas de noeud, il y a un cycle. Démarrer un DFS sur ce noeud. Lorsque vous traversez chaque arête, vérifiez si le bord pointe vers un noeud déjà présent sur votre pile. Cela indique l'existence d'un cycle. Si vous ne trouvez pas un tel bord, il n'y a pas de cycles dans ce composant connecté.
Comme Rutger Prins souligne, si votre graphique est pas connecté, vous devez répéter la recherche sur chaque composant connecté.
En tant que référence, Tarjan's strongly connected component algorithm est étroitement liée. Il vous aidera également à trouver les cycles, et pas seulement signaler s'ils existent.
BTW: Une arête qui "pointe vers un nœud déjà sur votre pile" est souvent appelée "arête arrière" dans la littérature, pour des raisons évidentes. Et oui, cela peut être plus simple que de trier le graphique topologiquement, surtout si vous avez besoin de faire un DFS de toute façon. – sleske
Pour que le graphique soit acyclique, vous dites que chaque composant connecté doit contenir un noeud avec uniquement des fronts sortants. Pouvez-vous recommander un algorithme pour trouver les composants connectés (par opposition aux composants "fortement" connectés) d'un graphe orienté, pour une utilisation par votre algorithme principal? – kostmo
@kostmo, si le graphe a plus d'un composant connecté, alors vous ne visiterez pas tous les noeuds de votre premier DFS. Gardez une trace des nœuds que vous avez visités, et répétez l'algorithme avec des nœuds non visités jusqu'à ce que vous les atteigniez tous. C'est essentiellement comment un algorithme de composants connectés fonctionne quand même. –
Lemme 22.11 sur le livre Introduction to Algorithms
(deuxième édition) stipule que:
Un graphe orienté G est acyclique si et seulement si une recherche en profondeur d'abord de G donne des bords sans retour
Je sais que c'est un vieux sujet mais pour les futurs chercheurs, voici une implémentation en C# que j'ai créée (pas de prétention que c'est le plus efficace!). Ceci est conçu pour utiliser un entier simple pour identifier chaque noeud. Vous pouvez décorer ce que vous voulez, à condition que votre objet de noeud hashes et égalise correctement.
Pour les graphiques très profonds cela peut avoir des frais généraux élevés, car il crée un HashSet à chaque noeud en profondeur (ils sont détruits sur la largeur).
entrée Vous le noeud à partir duquel vous souhaitez rechercher et le chemin à prendre ce nœud.
- Pour un graphique avec un seul nœud racine vous envoyer ce noeud et un HashSet
- vide Pour un graphique ayant plusieurs nœuds racine vous enveloppent cela dans un foreach sur ces noeuds et passer une nouvelle HashSet vide pour chaque itération
Lors de la vérification des cycles ci-dessous un nœud donné, il suffit de passer ce nœud avec un HashSet vide
private bool FindCycle(int node, HashSet<int> path) { if (path.Contains(node)) return true; var extendedPath = new HashSet<int>(path) {node}; foreach (var child in GetChildren(node)) { if (FindCycle(child, extendedPath)) return true; } return false; }
Voici mon œuvre rubis tion du peel off leaf node algorithm.
def detect_cycles(initial_graph, number_of_iterations=-1)
# If we keep peeling off leaf nodes, one of two things will happen
# A) We will eventually peel off all nodes: The graph is acyclic.
# B) We will get to a point where there is no leaf, yet the graph is not empty: The graph is cyclic.
graph = initial_graph
iteration = 0
loop do
iteration += 1
if number_of_iterations > 0 && iteration > number_of_iterations
raise "prevented infinite loop"
end
if graph.nodes.empty?
#puts "the graph is without cycles"
return false
end
leaf_nodes = graph.nodes.select { |node| node.leaving_edges.empty? }
if leaf_nodes.empty?
#puts "the graph contain cycles"
return true
end
nodes2 = graph.nodes.reject { |node| leaf_nodes.member?(node) }
edges2 = graph.edges.reject { |edge| leaf_nodes.member?(edge.destination) }
graph = Graph.new(nodes2, edges2)
end
raise "should not happen"
end
Solution1: algorithme Kahn pour vérifier le cycle. Idée principale: Maintenir une file d'attente où le noeud avec zéro au degré sera ajouté dans la file d'attente. Décollez ensuite le nœud un par un jusqu'à ce que la file d'attente soit vide. Vérifiez si les in-edges d'un nœud existent.
Solution2: Tarjan algorithme pour vérifier Composant connecté fort.
Solution3: DFS. Utilisez un tableau d'entiers pour marquer l'état actuel du noeud: , c'est-à-dire 0 - signifie que ce noeud n'a pas été visité auparavant. -1 - signifie que ce nœud a été visité et que ses nœuds enfants sont visités. 1 - signifie que ce noeud a été visité, et c'est fait. Donc, si l'état d'un nœud est de -1 alors que DFS est en cours, cela signifie qu'il doit exister un cycle.
Il ne devrait pas y avoir de bord arrière pendant que vous faites DFS. Gardez la trace des nœuds déjà visités en faisant DFS, si vous rencontrez une arête entre le nœud actuel et le nœud existant, alors le graphique a un cycle.
est ici un code rapide pour trouver si un graphe a des cycles:
func isCyclic(G : Dictionary<Int,Array<Int>>,root : Int , var visited : Array<Bool>,var breadCrumb : Array<Bool>)-> Bool
{
if(breadCrumb[root] == true)
{
return true;
}
if(visited[root] == true)
{
return false;
}
visited[root] = true;
breadCrumb[root] = true;
if(G[root] != nil)
{
for child : Int in G[root]!
{
if(isCyclic(G,root : child,visited : visited,breadCrumb : breadCrumb))
{
return true;
}
}
}
breadCrumb[root] = false;
return false;
}
let G = [0:[1,2,3],1:[4,5,6],2:[3,7,6],3:[5,7,8],5:[2]];
var visited = [false,false,false,false,false,false,false,false,false];
var breadCrumb = [false,false,false,false,false,false,false,false,false];
var isthereCycles = isCyclic(G,root : 0, visited : visited, breadCrumb : breadCrumb)
L'idée est comme ceci: un algorithme de DSF normale avec un tableau pour garder une trace des noeuds visités, et un tableau supplémentaire qui sert comme un marqueur pour les nœuds qui ont conduit au nœud actuel, de sorte que lorsque nous exécutons un dfs pour un nœud, nous définissons son élément correspondant dans le tableau des marqueurs comme vrai, de sorte que chaque fois qu'un nœud déjà visité rencontré, nous vérifions item dans le tableau des marqueurs est vrai, si c'est vrai alors c'est l'un des nœuds qui se laisse à (d'où un cycle), et l'astuce c'est quand un dfs d'un nœud retourne on met son marqueur correspondant à faux, de sorte que si nous l'avons visité d'une autre route, nous ne sommes pas dupes.
- 1. Un seul chemin le plus court d'un graphe acyclique non orienté déconnecté
- 2. Comment utiliser un graphe orienté BGL comme un graphe non orienté (à utiliser dans un algorithme de mise en page)?
- 3. Comment calculer le chemin critique d'un graphe acyclique directionnel?
- 4. Comment implémenter un graphe non orienté dans Ruby on Rails?
- 5. Nœuds feuille de graphe orienté - Prolog
- 6. Suggestions pour KSPA sur un graphe non orienté
- 7. Comment vérifier si un pointeur est valide?
- 8. Comment vérifier si FileObject est un dossier?
- 9. algorithme pour traveral BFS d'un graphe orienté de acylic
- 10. Stockage d'un graphe orienté dans google appengine datastore
- 11. Est-ce que le graphe orienté point autorise les sous-graphes avec un rangdir différent?
- 12. Comment modéliser un réseau bayésien ou, plus généralement, un graphe orienté, en SQL?
- 13. Comment vérifier si un caractère Java est un symbole monétaire
- 14. Possibilité de cracher un graphe acyclique dirigé à partir de Scons?
- 15. vérifier si un tableau est multidimensionnel
- 16. AS3: Vérifier si un dictionnaire est vide
- 17. vérifier si une chaîne est un double
- 18. Comment vérifier si DLL est compilé debug-
- 19. Comment vérifier si le formulaire est maximisé?
- 20. Comment vérifier si WordprocessingDocument est vide?
- 21. Comment vérifier si une session est invalide
- 22. Comment puis-je vérifier si un délégué est valide?
- 23. Comment vérifier si un utilisateur est toujours actif?
- 24. Plugin jQuery Validation: comment vérifier si un élément est valide?
- 25. Comment vérifier si un lien est actif ou non?
- 26. Comment vérifier si un périphérique USB donné est branché?
- 27. Comment vérifier si un module Perl est installé?
- 28. Comment vérifier si une valeur est un entier avec plpgsql?
- 29. Comment vérifier si un Socket est actuellement connecté en Java?
- 30. comment vérifier si un fichier est sélectionné avec javascript?
Un autre cas en faveur d'une certaine façon de "réparer" les mauvaises réponses sur SO. – Sparr
Donc, euh, je suis surtout intéressé par le temps nécessaire pour le trouver. Donc, j'ai juste besoin de l'algorithme abstrait. – nes1983
vous devez traverser tous les bords et vérifier tous les sommets donc la limite inférieure est O (| V | + | E |). DFS et BFS sont tous deux de la même complexité mais DFS est plus facile à coder si vous avez une récursivité car cela gère la pile pour vous ... – ShuggyCoUk