web-dev-qa-db-fra.com

Utilisation de BFS pour les graphiques pondérés

Je révisais les algorithmes de chemin le plus court à source unique et dans la vidéo, l'enseignant mentionne que BFS/DFS ne peut pas être utilisé directement pour trouver les chemins les plus courts dans un graphique pondéré (je suppose que tout le monde le sait déjà) et dit de fonctionner par vous-même.

Je me demandais la raison/explication exacte pour laquelle il ne pouvait pas être utilisé pour les graphiques pondérés. Est-ce dû au poids des bords ou à autre chose? Quelqu'un peut-il m'expliquer alors que je me sens un peu confus.

PS: J'ai parcouru cette question et cette question.

20
user2125722

Considérez un graphique comme celui-ci:

A---(3)-----B
|           |
\-(1)-C--(1)/

Le chemin le plus court de A à B est via C (avec un poids total de 2). Un BFS normal prendra le chemin directement de A à B, marquant B comme vu, et de A à C, marquant C comme vu.

À l'étape suivante, la propagation à partir de C, B est déjà marquée comme visible, donc le chemin de C à B ne sera pas considéré comme un chemin potentiellement plus court, et le BFS vous dira que le chemin le plus court de A à B a un poids de 3.

Vous pouvez utiliser algorithme de Dijkstra au lieu de BFS pour trouver le chemin le plus court sur un graphique pondéré. Fonctionnellement, l'algorithme est très similaire à BFS et peut être écrit de manière similaire à BFS. La seule chose qui change est l'ordre dans lequel vous considérez les nœuds.

Par exemple, dans le graphique ci-dessus, en commençant par A, un BFS traitera A -> B, puis A -> C, et s'arrêtera là car tous les nœuds ont été vus.

D'un autre côté, l'algorithme de Dijkstra fonctionnera comme suit:

  1. Considérez A -> C (puisque c'est le poids de bord le plus bas de A)
  2. Considérez C -> B (puisque c'est le bord le plus léger de n'importe quel nœud que nous avons atteint jusqu'à présent, que nous n'avons pas encore considéré)
  3. Considérez et ignorez A -> B puisque B a déjà été vu.

Notez que la différence réside simplement dans l'ordre dans lequel les bords sont inspectés. Un BFS considérera tous les bords d'un nœud unique avant de passer à d'autres nœuds, tandis que l'algorithme de Dijkstra considérera toujours le poids le plus faible invisible Edge, à partir de l'ensemble des bords connectés à tous les nœuds qui ont été vus jusqu'à présent . Cela peut sembler déroutant, mais le pseudocode est très simple:

create a heap or priority queue
place the starting node in the heap
dist[2...n] = {∞}
dist[1] = 0
while the heap contains items:
   vertex v = top of heap
   pop top of heap
   for each vertex u connected to v:
       if dist[u] > dist[v] + weight of v-->u:
           dist[u] = dist[v] + weight of Edge v-->u
           place u on the heap with weight dist[u]

Ce GIF de Wikipedia fournit une bonne visualisation de ce qui se passe:

Dijkstra

Notez que cela ressemble beaucoup au code BFS, la seule vraie différence est l'utilisation d'un tas, trié par distance au nœud, au lieu d'une structure de données de file d'attente régulière .

33
Greg

Bien que cela soit vrai, mais vous pouvez utiliser BFS/DFS dans les graphiques pondérés, avec un petit changement dans le graphique, si les poids de votre graphique sont des entiers positifs, vous pouvez remplacer un Edge par le poids n par n les bords par le poids 1 avec n-1 nœuds intermédiaires. Quelque chose comme ça:

A-(4)-B

sera:

A-(1)-M1-(1)-M2-(1)-M3-(1)-B

Et ne tenez pas compte de ces nœuds intermédiaires (comme M1, M2, M3) dans vos résultats finaux BFS/DFS.


Cette complexité d'algorithme est O (V * M) et M est le poids maximum de nos bords, si nous savons que dans nos graphiques particuliers M<log V cet algorithme pourrait être considéré, mais en général cet algorithme peut ne pas avoir de si bonnes performances.

3
Lrrr