Tôi có đúng về sự khác biệt giữa các thuật toán Floyd-Warshall, Dijkstra và Bellman-Ford không?


12

Tôi đã nghiên cứu ba và tôi nói rằng những suy luận của tôi từ họ bên dưới. Ai đó có thể cho tôi biết nếu tôi đã hiểu họ đủ chính xác hay không? Cảm ơn bạn.

  1. Thuật toán của Dijkstra chỉ được sử dụng khi bạn có một nguồn duy nhất và bạn muốn biết đường dẫn nhỏ nhất từ ​​nút này sang nút khác, nhưng không thành công trong trường hợp như thế này

  2. Thuật toán của Floyd-Warshall được sử dụng khi bất kỳ nút nào trong số tất cả các nút có thể là nguồn, vì vậy bạn muốn khoảng cách ngắn nhất để đến bất kỳ nút đích nào từ bất kỳ nút nguồn nào. Điều này chỉ thất bại khi có chu kỳ âm

(đây là điều quan trọng nhất. Ý tôi là, đây là điều tôi ít chắc chắn nhất :)

3.Bellman-Ford được sử dụng như Dijkstra, khi chỉ có một nguồn. Điều này có thể xử lý các trọng số âm và hoạt động của nó giống như của Floyd-Warshall ngoại trừ một nguồn, phải không?

Nếu bạn cần phải có một cái nhìn, các thuật toán tương ứng là (Wikipedia lịch sự):

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] );

Tôi khá chắc chắn rằng thuật toán của Dijkstra có thể xử lý các nút có trọng số âm. Nếu có chu kỳ trọng số âm, đường dẫn ngắn nhất là không xác định, bất kể thuật toán.
kevin cline

1
@kevincline: Wikipedia không hỗ trợ yêu cầu của bạn (Tôi không tuyên bố wikipedia là đúng mặc dù, và tôi có AlgTheory tôi đặt vài trăm dặm) Tuy nhiên, trong thực tế cuộc sống khó khăn theo thời gian hoặc tốc độ dựa trên định tuyến có không có cạnh tiêu cực, vì vậy tôi thường làm Dijsktra hoặc Floyd, tùy theo nhu cầu. Theo như tôi nhớ, hầu hết các thuật toán định tuyến bản đồ thực tế đều dựa trên phiên bản hiện đại hóa của Dijsktra, nhưng tôi chỉ nhớ nó từ một số bài báo khoa học tôi đã đọc tại nơi làm việc trước đây.
Aadaam

@Aadaam: Tôi sai rồi. Dijkstra khai thác không tiêu cực để tránh truy cập mọi khía cạnh.
kevin cline

Vâng, bạn đã hiểu chính xác. :)
Sanghyun Lee

Câu trả lời:


3

Nếu tôi hiểu bạn chính xác, sự hiểu biết của bạn là chính xác.

  • Djikstra tìm thấy đường dẫn chi phí nhỏ nhất từ ​​một nút nguồn đến mọi nút khác trong biểu đồ, ngoại trừ nếu có cạnh trọng số âm. (Dijkstra có thể dễ dàng chuyển đổi thành thuật toán A * bằng cách thay đổi nó thành dừng khi tìm thấy nút mục tiêu và thêm phương pháp phỏng đoán.)
  • Bellman-Ford làm tương tự như Dijkstra, nhưng chậm hơn. Nhưng nó có thể xử lý các cạnh trọng lượng tiêu cực.
  • Floyd-Warshall tìm thấy chi phí của đường dẫn chi phí nhỏ nhất từ ​​mỗi nút đến mọi nút khác. (Nó trả về một ma trận số.) Nó chậm hơn nhiều so với Djikstra hoặc Bellman-Ford. Không giống như những gì bạn đã viết, nó không thất bại khi một chu kỳ tiêu cực xảy ra, nó chỉ báo cáo một số âm vô nghĩa cho chi phí của một số nút cho chính nó.

1
Nah, Floyd-Warshall có thể tự tính toán các đường dẫn, giống như Djikstra và Bellman-Ford, không chỉ là độ dài đường dẫn.
Konrad Rudolph

Với sửa đổi, tất nhiên.
Ceasar Bautista

3
Tôi vẫn sẽ coi cái đầu tiên là của Dijkstra nếu nó bị dừng ở nút mục tiêu, nhưng không sử dụng phương pháp phỏng đoán.
Bóng Eliot

1
@CSA - Floyd Warshall là O (n ^ 3), vì vậy sẽ cần khoảng 10 ^ 300 thao tác cho một biểu đồ lớn như vậy. Giả sử mỗi hoạt động cần có thời gian Planck, đến khi tính toán kết thúc tất cả các proton trong vật chất thông thường trong vũ trụ sẽ bị phân rã, và chỉ còn lại các lỗ đen siêu lớn . Tôi tin rằng có thể song song với vòng lặp bên trong. Nếu điều này là đúng, bạn có thể may mắn hoàn thành trước khi tất cả các lỗ đen bắt đầu với khối lượng mặt trời đã bốc hơi.
Jules

1
(Giả sử bạn có thể xây dựng một nút xử lý bằng cách sử dụng ít hơn một nguyên tử trên mỗi quy trình và có thể sử dụng tất cả các nguyên tử trong vũ trụ quan sát được, đó là ... nhưng sau đó bạn có thể cần tất cả các nguyên tử đó để lưu trữ dữ liệu của mình để bắt đầu)
Jules
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.