web-dev-qa-db-fra.com

Comment fonctionne une recherche approfondie en premier lorsque vous recherchez le chemin le plus court?

J'ai fait des recherches et il me semble qu'il me manque une petite partie de cet algorithme. Je comprends le fonctionnement d'une recherche en largeur d'abord, mais je ne comprends pas comment exactement cela me mènera à un chemin spécifique, au lieu de me dire simplement où chaque nœud individuel peut aller. Je suppose que la meilleure façon d’expliquer ma confusion est de donner un exemple:

Donc, par exemple, disons que j'ai un graphique comme celui-ci:

enter image description here

Et mon objectif est de passer de A à E (toutes les arêtes ne sont pas pondérées).

Je commence par A, parce que c'est mon origine. Je fais la queue A, suivi immédiatement de la file d'attente A et de l'exploration. Ceci donne B et D, car A est connecté à B et D. Je mets donc en file d'attente B et D.

Je retire la file B et l'explore, et trouve qu'elle mène à A (déjà exploré), et C, alors je fais la queue C. Je file alors D et trouve qu'elle mène à E, mon objectif. Je retire alors C et trouve que cela mène également à E, mon objectif.

Je sais logiquement que le chemin le plus rapide est A-> D-> E, mais je ne sais pas exactement comment la recherche en largeur d'abord est utile - comment devrais-je enregistrer des chemins tels que lorsque je termine, je peux analyser les résultats et voir que le chemin le plus court est A-> D-> E?

De plus, notez que je n'utilise pas réellement d'arborescence, il n'y a donc pas de nœud "parent", uniquement des enfants.

111
Jake

Techniquement, la recherche en largeur par la première ne permet pas de trouver le chemin le plus court, simplement parce que BFS ne recherche pas le chemin le plus court: BFS décrit une stratégie de recherche de graphique, mais n'indique pas que vous devez rechercher rien en particulier.

algorithme de Dijkstra adapte BFS pour vous permettre de trouver les chemins les plus courts provenant d'une source unique.

Afin de récupérer le chemin le plus court de l'origine à un nœud, vous devez gérer deux éléments pour chaque nœud du graphique: la distance la plus courte en cours et le nœud précédent dans le chemin le plus court. Initialement, toutes les distances sont définies à l'infini et tous les prédécesseurs sont définis pour être vides. Dans votre exemple, définissez la distance de A sur zéro, puis procédez au BFS. À chaque étape, vous vérifiez si vous pouvez améliorer la distance d'un descendant, c'est-à-dire que la distance entre l'origine et le prédécesseur, plus la longueur du bord que vous explorez, est inférieure à la meilleure distance actuelle pour le nœud en question. Si vous pouvez améliorer la distance, définissez le nouveau chemin le plus court et souvenez-vous du prédécesseur par lequel ce chemin a été acquis. Lorsque la file d'attente BFS est vide, choisissez un nœud (dans votre exemple, il s'agit de E) et repoussez ses prédécesseurs dans l'origine. Cela vous donnerait le chemin le plus court.

Si cela semble un peu déroutant, wikipedia a un Nice section pseudocode sur le sujet.

71
dasblinkenlight

Comme indiqué ci-dessus, BFS peut uniquement être utilisé pour trouver le chemin le plus court dans un graphique si:

  1. Il n'y a pas de boucles

  2. Tous les bords ont le même poids ou pas de poids.

Pour trouver le chemin le plus court, tout ce que vous avez à faire est de commencer à partir de la source et d'effectuer une première recherche étendue puis de vous arrêter lorsque vous trouvez votre nœud de destination. La seule chose supplémentaire à faire est d’avoir un tableau précédent [n] qui stockera le noeud précédent pour chaque noeud visité. Le précédent de source peut être null.

Pour imprimer le chemin, il suffit de parcourir le tableau [] précédent depuis la source jusqu'à atteindre la destination et d'imprimer les nœuds. DFS peut également être utilisé pour trouver le chemin le plus court dans un graphique dans des conditions similaires.

Toutefois, si le graphe est plus complexe et contient des arêtes et des boucles pondérées, nous avons besoin d’une version plus sophistiquée de BFS, à savoir l’algorithme de Dijkstra.

43
javaProgrammer

De tutoriel ici

"Il a la propriété extrêmement utile que si toutes les arêtes d'un graphe ne sont pas pondérées (ou le même poids), alors la première fois qu'un nœud est visité est le chemin le plus court vers ce nœud depuis le nœud source"

20
acheron55

J'ai perdu 3 jours
a finalement résolu une question de graphique
utilisé pour
trouver la distance la plus courte
utilisant BFS

Envie de partager l'expérience.

When the (undirected for me) graph has
fixed distance (1, 6, etc.) for edges

#1
We can use BFS to find shortest path simply by traversing it
then, if required, multiply with fixed distance (1, 6, etc.)

#2
As noted above
with BFS
the very 1st time an adjacent node is reached, it is shortest path

#3
It does not matter what queue you use
   deque/queue(c++) or
   your own queue implementation (in c language)
   A circular queue is unnecessary

#4
Number of elements required for queue is N+1 at most, which I used
(dint check if N works)
here, N is V, number of vertices.

#5
Wikipedia BFS will work, and is sufficient.
    https://en.wikipedia.org/wiki/Breadth-first_search#Pseudocode

J'ai perdu 3 jours à essayer toutes les solutions ci-dessus, à vérifier et à vérifier encore et encore ci-dessus
Ils ne sont pas la question.
(Essayez de passer du temps à la recherche d’autres problèmes, si vous trouvez des problèmes avec l’article 5).


Plus d'explication du commentaire ci-dessous:

      A
     /  \
  B       C
 /\       /\
D  E     F  G

Supposez ci-dessus est votre graphique
graphique descend
Pour A, les adjacentes sont B & C
Pour B, les adjacentes sont D & E
Pour C, les adjacentes sont F & G

dire, le noeud de départ est A

  1. lorsque vous atteignez A, B & C, la distance la plus courte entre B et C et A est 1

  2. lorsque vous atteignez D ou E, B, la distance la plus courte entre A et D est de 2 (A-> B-> D)

de même, A-> E vaut 2 (A-> B-> E)

aussi, A-> F & A-> G est 2

Donc, maintenant, au lieu de 1 distance entre les nœuds, si elle est 6, il suffit de multiplier la réponse par 6
exemple,
si la distance entre chacun est 1, alors A-> E est 2 (A-> B-> E = 1 + 1)
si la distance entre chacun est 6, alors A-> E est 12 (A-> B-> E = 6 + 6)

oui, bfs peut prendre n'importe quel chemin
mais nous calculons pour tous les chemins

si vous devez aller de A à Z, nous empruntons tous les chemins de A à un I intermédiaire, et comme il y aura de nombreux chemins, nous écarterons tous les chemins sauf le plus court jusqu'à I, puis nous poursuivrons avec le chemin le plus court jusqu'au noeud suivant J
à nouveau s'il y a plusieurs chemins de I à J, nous prenons seulement le plus court chemin
exemple,
présumer,
A -> I nous avons la distance 5
(STEP) supposons, I -> J nous avons plusieurs chemins, de distances 7 & 8, puisque 7 est le plus court
on prend A -> J comme 5 (A-> I le plus court) + 8 (le plus court maintenant) = 13
alors A-> J est maintenant 13
nous répétons maintenant ci-dessus (STEP) pour J -> K et ainsi de suite, jusqu'à arriver à Z

Lisez cette partie, 2 ou 3 fois, et dessinez sur papier, vous obtiendrez sûrement ce que je dis, bonne chance


8

Basé sur réponse acheron55 j'ai posté une implémentation possible ici .
En voici un bref résumé:

Tout ce que vous avez à faire est de garder trace du chemin par lequel la cible a été atteinte. Un moyen simple de le faire est d'insérer dans le Queue le chemin complet utilisé pour atteindre un nœud, plutôt que le nœud lui-même.
L'avantage de le faire est que lorsque la cible est atteinte, la file d'attente contient le chemin utilisé pour l'atteindre.
Ceci s’applique également aux graphiques cycliques, dans lesquels un nœud peut avoir plusieurs parents.

1
c0der