Ai-je raison sur les différences entre les algorithmes de Floyd-Warshall, Dijkstra et Bellman-Ford?


12

J'ai étudié les trois et j'énonce mes inférences ci-dessous. Quelqu'un pourrait-il me dire si je les ai suffisamment compris ou non? Je vous remercie.

  1. L'algorithme de Dijkstra est utilisé uniquement lorsque vous avez une seule source et que vous souhaitez connaître le plus petit chemin d'un nœud à un autre, mais échoue dans des cas comme celui-ci

  2. L'algorithme de Floyd-Warshall est utilisé lorsque tous les nœuds peuvent être une source, vous voulez donc que la distance la plus courte atteigne n'importe quel nœud de destination à partir de n'importe quel nœud source. Cela échoue uniquement lorsqu'il y a des cycles négatifs

(c'est le plus important. Je veux dire, c'est celui dont je suis le moins sûr :)

3.Bellman-Ford est utilisé comme Dijkstra, lorsqu'il n'y a qu'une seule source. Cela peut gérer les poids négatifs et son fonctionnement est le même que celui de Floyd-Warshall, sauf pour une source, non?

Si vous avez besoin d'y jeter un œil, les algorithmes correspondants sont (avec la permission de Wikipedia):

Bellman-Ford:

 procedure BellmanFord(list vertices, list edges, vertex source)
   // This implementation takes in a graph, represented as lists of vertices
   // and edges, and modifies the vertices so that their distance and
   // predecessor attributes store the shortest paths.

   // Step 1: initialize graph
   for each vertex v in vertices:
       if v is source then v.distance := 0
       else v.distance := infinity
       v.predecessor := null

   // Step 2: relax edges repeatedly
   for i from 1 to size(vertices)-1:
       for each edge uv in edges: // uv is the edge from u to v
           u := uv.source
           v := uv.destination
           if u.distance + uv.weight < v.distance:
               v.distance := u.distance + uv.weight
               v.predecessor := u

   // Step 3: check for negative-weight cycles
   for each edge uv in edges:
       u := uv.source
       v := uv.destination
       if u.distance + uv.weight < v.distance:
           error "Graph contains a negative-weight cycle"

Dijkstra:

 1  function Dijkstra(Graph, source):
 2      for each vertex v in Graph:                                // Initializations
 3          dist[v] := infinity ;                                  // Unknown distance function from 
 4                                                                 // source to v
 5          previous[v] := undefined ;                             // Previous node in optimal path
 6                                                                 // from source
 7      
 8      dist[source] := 0 ;                                        // Distance from source to source
 9      Q := the set of all nodes in Graph ;                       // All nodes in the graph are
10                                                                 // unoptimized - thus are in Q
11      while Q is not empty:                                      // The main loop
12          u := vertex in Q with smallest distance in dist[] ;    // Start node in first case
13          if dist[u] = infinity:
14              break ;                                            // all remaining vertices are
15                                                                 // inaccessible from source
16          
17          remove u from Q ;
18          for each neighbor v of u:                              // where v has not yet been 
19                                                                                 removed from Q.
20              alt := dist[u] + dist_between(u, v) ;
21              if alt < dist[v]:                                  // Relax (u,v,a)
22                  dist[v] := alt ;
23                  previous[v] := u ;
24                  decrease-key v in Q;                           // Reorder v in the Queue
25      return dist;

Floyd-Warshall:

 1 /* Assume a function edgeCost(i,j) which returns the cost of the edge from i to j
 2    (infinity if there is none).
 3    Also assume that n is the number of vertices and edgeCost(i,i) = 0
 4 */
 5
 6 int path[][];
 7 /* A 2-dimensional matrix. At each step in the algorithm, path[i][j] is the shortest path
 8    from i to j using intermediate vertices (1..k−1).  Each path[i][j] is initialized to
 9    edgeCost(i,j).
10 */
11
12 procedure FloydWarshall ()
13    for k := 1 to n
14       for i := 1 to n
15          for j := 1 to n
16             path[i][j] = min ( path[i][j], path[i][k]+path[k][j] );

Je suis presque sûr que l'algorithme de Dijkstra peut gérer les nœuds de poids négatif. S'il y a des cycles de poids négatifs, le chemin le plus court n'est pas défini, quel que soit l'algorithme.
kevin cline

1
@kevincline: Wikipedia ne prend pas en charge votre affirmation (je ne prétends pas que wikipedia a raison cependant, et j'ai mon livre AlgTheory à quelques centaines de kilomètres) Cependant, dans les problèmes de routage basés sur le temps ou la vitesse réels, il y a pas de bords négatifs, donc je fais habituellement du Dijsktra ou du Floyd, selon le besoin. Pour autant que je m'en souvienne, la plupart des algos de routage cartographiques réels sont basés sur une version modernisée de Dijsktra, mais je m'en souviens juste de certains articles scientifiques que j'ai lus sur mon lieu de travail précédent.
Aadaam

@Aadaam: Je me trompe. Dijkstra exploite la non-négativité pour éviter de visiter chaque bord.
kevin cline

Oui, vous avez bien compris. :)
Sanghyun Lee

Réponses:


3

Si je vous comprends bien, votre compréhension est correcte.

  • Djikstra trouve le plus petit chemin de coût d'un nœud source à tous les autres nœuds dans le graphique, sauf s'il y a un bord de poids négatif. (Dijkstra peut être facilement transformé en l'algorithme A * en le changeant simplement pour s'arrêter une fois qu'il a trouvé le nœud cible et en ajoutant des heuristiques.)
  • Bellman-Ford fait la même chose que Dijkstra, mais est plus lent. Mais il peut gérer des bords de poids négatifs.
  • Floyd-Warshall trouve le coût du plus petit chemin de coût de chaque nœud à chaque autre nœud. (Il renvoie une matrice numérique.) Il est beaucoup plus lent que Djikstra ou Bellman-Ford. Contrairement à ce que vous avez écrit, il n'échoue pas lorsqu'un cycle négatif se produit, il rapporte simplement un nombre négatif insignifiant pour le coût d'un nœud.

1
Non, Floyd-Warshall peut calculer les chemins eux-mêmes, comme Djikstra et Bellman-Ford, pas seulement les longueurs de chemin.
Konrad Rudolph

Avec des modifications, bien sûr.
Ceasar Bautista

3
Je considérerais toujours le premier comme celui de Dijkstra s'il était arrêté sur un nœud cible, mais je n'utilisais pas d'heuristique.
Eliot Ball

1
@CSA - Floyd Warshall est O (n ^ 3), donc environ 10 ^ 300 opérations seraient nécessaires pour un si grand graphique. En supposant que chaque opération prend du temps Planck, au moment où le calcul a terminé tous les protons dans la matière régulière de l'univers auront pourri, et seuls les trous noirs supermassifs resteront . Je pense qu'il peut être possible de paralléliser la boucle intérieure. Si cela est vrai, vous aurez peut-être la chance de terminer avant que tous les trous noirs qui ont commencé avec la masse du soleil se soient évaporés.
Jules

1
(En supposant que vous pouvez créer un nœud de traitement en utilisant moins d'un atome par processus, et que vous pouvez utiliser tous les atomes de l'univers observable, c'est-à-dire ... mais alors vous avez probablement besoin de tous ceux-ci pour stocker vos données pour commencer)
Jules
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.