Прав ли я насчет различий между алгоритмами Флойда-Уоршелла, Дейкстры и Беллмана-Форда?

Я изучал три, и я излагаю свои выводы из них ниже. Может ли кто-нибудь сказать мне, понял ли я их достаточно точно или нет? Спасибо.

  1. алгоритм Дейкстры используется только тогда, когда у вас есть один источник, и вы хотите знать наименьший путь от одного узла к другому, но терпит неудачу в таких случаях, как этой

  2. Флойд-Warshall используется, когда ни один из всех узлов может быть источником, так что вы требуется кратчайшее расстояние для достижения любого узла назначения из любого исходного узла. Это только терпит неудачу, когда есть отрицательные циклы

(это самый важный. Я имею в виду, это тот, в котором я меньше всего уверен:)

3.Bellman-Ford используется как Dijkstra, когда есть только один источник. Это может обрабатывать отрицательные веса и его работа такая же, как у Floyd-Warshall, за исключением одного источника, верно?

Если вам нужно посмотреть соответствующие алгоритмы (спасибо Википедии):

Беллмана-Форда:

 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"

Дейкстра:

 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;

Флойд-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] );

2 ответов


вы правы в первых двух вопросах и о цели Floyd-Warshall (поиск кратчайших путей между всеми парами), но не об отношениях между Bellman-Ford и Floyd-Warshall: оба алгоритма используют динамическое программирование для поиска кратчайшего пути, но FW не то же самое, что запуск BF от каждого начального узла до каждого другого узла.

в BF возникает вопрос: каков кратчайший путь от источника к цели, используя не более k шагов, и работает время O (EV). Если бы мы должны были запустить его на другой узел, время работы было бы O (EV^2).

в FW возникает вопрос: каков кратчайший путь от i до j через k для всех узлов i, j,k. Это приводит к O (V^3) времени работы - лучше, чем BF для каждого начального узла (в разы до |V| для плотных графов).

еще одно замечание о отрицательных циклах / весах: Dijkstra может просто не дать правильных результатов. BF и FW не подведут - они будут правильно заявите, что нет минимального пути веса, так как отрицательный вес неограничен.


один источник кратчайших путей:

алгоритм Дейкстры-отрицательный вес не допускается-O(E+Vlg (V))

алгоритм Bellman ford-отрицательный вес разрешен. Но если отрицательный цикл присутствует, Bellman ford обнаружит-ve cycle-O(VE)

направленный ациклический граф - как следует из названия, он работает только для DAG-O(V+E)

все пары кратчайших путей:

алгоритм Дейкстры - отрицательный вес не допускается-O(VE + V^2lg (V))

алгоритм Беллмана Форда-O (V^2E)

метод умножения матричной цепи-сложность такая же, как алгоритм Беллмана Форда

для Floyd Warshall метода динамического программирования - сложность o(П^3)