420 votes

Quelles détections de cycle au sein d'un graphe dirigé sont plus efficaces que O(n^2) ?

Existe-t-il un algorithme plus efficace en termes de temps que O(n^2) pour détecter les cycles au sein d'un graphe orienté?

J'ai un graphe orienté représentant un emploi du temps des tâches à exécuter, une tâche étant un noeud et une dépendance étant une arête. Je dois détecter le cas d'erreur d'un cycle au sein de ce graphe entraînant des dépendances cycliques.

16 votes

Vous dites que vous voulez détecter tous les cycles, mais votre cas d'utilisation suggère qu'il serait suffisant de détecter s'il y a des cycles.

35 votes

Il serait préférable de détecter tous les cycles afin de les corriger en une seule fois, plutôt que de vérifier, corriger, vérifier, corriger, etc.

2 votes

Vous devriez lire l'article "Finding all the elementary circuits of a directed graph" de Donald B. Johnson. Il trouvera uniquement les circuits élémentaires, mais cela devrait être suffisant pour votre cas. Et voici mon implémentation en Java de cet algorithme prête à être utilisée : github.com/1123/johnson

29voto

Ajay Garg Points 81

Commencez par un DFS : un cycle existe si et seulement si une arête arrière est découverte pendant le DFS. Cela est prouvé grâce au théorème du chemin blanc.

4 votes

Oui, je pense la même chose, mais cela ne suffit pas, je publie ma voie cs.stackexchange.com/questions/7216/find-the-simple-cycles-i‌​n-a-directed-graph

0 votes

Vrai. Ajay Garg ne fait que parler de comment trouver "un cycle", ce qui est une partie de la réponse à cette question. Votre lien parle de trouver tous les cycles selon la question posée, mais il semble à nouveau utiliser la même approche qu'Ajay Garg, mais fait également tous les arbres dfs possibles.

0 votes

Ceci est incomplet pour les graphes dirigés. Voir la réponse correcte de Kurt Peek.

9voto

Aaron Digulla Points 143830

Si vous ne pouvez pas ajouter une propriété "visited" aux nœuds, utilisez un ensemble (ou une map) et ajoutez simplement tous les nœuds visités à l'ensemble sauf s'ils sont déjà dans l'ensemble. Utilisez une clé unique ou l'adresse des objets comme "clé".

Cela vous donne également des informations sur le nœud "racine" de la dépendance cyclique ce qui sera utile lorsque l'utilisateur devra résoudre le problème.

Une autre solution est d'essayer de trouver la prochaine dépendance à exécuter. Pour cela, vous devez avoir une pile où vous pouvez vous souvenir de où vous êtes maintenant et de ce que vous devez faire ensuite. Vérifiez si une dépendance est déjà sur cette pile avant de l'exécuter. Si c'est le cas, vous avez trouvé un cycle.

Alors que cela peut sembler avoir une complexité de O(N*M), vous devez vous rappeler que la pile a une profondeur très limitée (donc N est petit) et que M devient plus petit à chaque dépendance que vous pouvez cocher comme "exécutée" en plus vous pouvez arrêter la recherche lorsque vous trouvez une feuille (donc vous n'avez jamais à vérifier chaque nœud -> M sera également petit).

Dans MetaMake, j'ai créé le graphe comme une liste de listes puis j'ai supprimé chaque nœud au fur et à mesure que je les exécutais ce qui a naturellement réduit le volume de recherche. Je n'ai jamais eu besoin d'exécuter une vérification indépendante, tout s'est passé automatiquement pendant l'exécution normale.

Si vous avez besoin d'un mode "test uniquement", ajoutez simplement un indicateur "dry-run" qui désactive l'exécution des tâches réelles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X