ფლოიდ-ვორშელი: დპ გრაფზე

მარშრუტიზაციის ცხრილს ყველა წყვილ მარშრუტიზატორს შორის მანძილი სჭირდება და არა მხოლოდ ერთი წყაროდან. ფლოიდ-ვორშელი ყველას სამი ჩალაგებული ციკლითა და კოდის ხუთი ხაზით ითვლის, და ეს გრაფზე დპ-ის ყველაზე სუფთა მაგალითია.

მოწინავე⏱ 12 წთ
01

ისწავლე

იდეა, მექანიზმი და ფასი.

01ყველა წყვილი ერთდროულად

დეიქსტრა მანძილებს ერთი წყაროდან იძლევა. ყველა წყვილისთვის მისი V-ჯერ გაშვება შეიძლებოდა, მაგრამ უარყოფითი წიბოებით ის ცდება, ბელმან-ფორდის V-ჯერ გაშვება კი O(V²E) ღირს.

ფლოიდ-ვორშელი მუშაობს მანძილების მატრიცაზე d[i][j]: ვიწყებთ წიბოს წონით იქ, სადაც წიბო არსებობს, დიაგონალზე 0-ით და სხვაგან ∞-ით. დასრულებისას d[i][j] უმოკლესი მანძილია i-დან j-მდე ყველა წყვილისთვის. ის უარყოფით წიბოებსაც უმკლავდება, თუ უარყოფითი ციკლი არ არის (თორემ „უმოკლესს“ აზრი აღარ აქვს).

მაგალითის გრაფში ორი წიბო უარყოფითია. 1-დან 2-მდე უიაფესი გზა საერთოდ არ არის პირდაპირი წიბო: 1 → 3 → 4 → 2 ღირს −2 + 2 − 1 = −1. ასეთი მარშრუტების პოვნა 16-ვე წყვილისთვის არის ამოცანა.

უარყოფითი წიბოები, ციკლის გარეშე-2432-112341 → 2 უმოკლესი გზა: 1 → 3 → 4 → 2 = −2 + 2 − 1 = −1

02დპ-ის მდგომარეობა: რომელი წვეროები შეიძლება იყოს შუაში

მთავარი ხრიკი მდგომარეობაშია. გადავნომროთ წვეროები 1..V და განვსაზღვროთ

d_k[i][j] = უმოკლესი გზა i-დან j-მდე, რომლის ყველა შუალედური წვერო {1, …, k}-შია.

k = 0-ზე შუალედური წვეროები არ შეიძლება, ამიტომ d₀ წიბოების მატრიცაა. k−1-დან k-ზე გადასვლისას უმოკლესი გზა ან არ იყენებს k წვეროს (მაშინ ის d_{k−1}[i][j]-ია), ან იყენებს ზუსტად ერთხელ და იყოფა i → k და k → j ნაწილებად, ორივე {1, …, k−1}-დან შუალედურებით:

d_k[i][j] = min(d_{k−1}[i][j], d_{k−1}[i][k] + d_{k−1}[k][j])

k = V-ის შემდეგ ყველა წვერო დასაშვებია, ამიტომ d_V ნამდვილ მანძილებს ინახავს. გვაქვს V ფენა, თითოში V² უჯრა, თითო O(1), ჯამში O(V³).

dₖ[i][j]: შუალედურად მხოლოდ 1..k წვეროებიk-ს გარეშე: dₖ₋₁[i][j]ijkk-ზე გავლითdₖ[i][j] = min( dₖ₋₁[i][j], dₖ₋₁[i][k] + dₖ₋₁[k][j] )

03ხუთი ხაზი და ერთი წესი ციკლების რიგზე

კოდში V მატრიცა არ გვჭირდება. ერთ მატრიცას ადგილზე ვაახლებთ:

for k: for i: for j: d[i][j] = min(d[i][j], d[i][k] + d[k][j])

ეს უსაფრთხოა, რადგან k-ურ რაუნდში d[i][k] და d[k][j] არ იცვლება (k-მდე მისასვლელად k-ზე გავლა ვერ დაგვეხმარება).

ერთადერთი წესი: k ყველაზე გარე ციკლი უნდა იყოს. ის დპ-ის ფენაა, i და j კი ამ ფენის უჯრებია. k-ს შიგნით ჩასმა ზოგ გრაფზე არასწორ პასუხს იძლევა, ეს კლასიკური შეცდომაა.

ორი ბონუსი. განახლებისას შეინახე next[i][j], რომ გზები აღადგინო. ციკლების შემდეგ კი ნებისმიერი d[i][i] < 0 i-ზე გამავალ უარყოფით ციკლს ავლენს. O(V³) დროითა და O(V²) მეხსიერებით ფლოიდ-ვორშელი სწორი არჩევანია, როცა V დაახლოებით 400–500-მდეა, გრაფი მკვრივია ან მართლა ყველა წყვილი გჭირდება.

დასაწყისი: მხოლოდ წიბოები123412340∞-2∞403∞∞∞02∞-1∞0k = 1, 2, 3, 4-ის შემდეგ123412340-1-20402451023-110d[i][i] < 0 ⇒ უარყოფითი ციკლი
მწვანე უჯრები შუალედურ წვეროზე გავლით გაუმჯობესდა.

ფასი ერთი შეხედვით

უმოკლესი გზები ყველა წყვილს შორისO(V³)
მეხსიერება (ერთი მატრიცა)O(V²)
უარყოფითი ციკლის შემოწმებაO(V)

დაიმახსოვრე

  1. მდგომარეობა d_k[i][j] შუაში მხოლოდ 1..k წვეროებს უშვებს; k წვეროს დამატება ან ეხმარება i → k → j გზით, ან არა.
  2. k ყველაზე გარე ციკლად დატოვე; ადგილზე განახლებული ერთი მატრიცა საკმარისია.
  3. ის უარყოფით წიბოებთან მუშაობს, ხოლო შემდეგ დიაგონალზე უარყოფითი მნიშვნელობა უარყოფით ციკლზე მიუთითებს.
02

ითამაშე

გაიარე ალგორითმი ბიჯ-ბიჯ, მერე სცადე შენს მონაცემებზე.

👀 რას უყურო: ყოველი ფაზა კიდევ ერთ შუალედურ წვეროს k-ს ხსნის; უყურე, მატრიცის რომელი უჯრები მცირდება, და შეამოწმე გრაფში k-ზე გამავალი მარშრუტებით.

ინტერაქტიული ვიზუალიზატორიაქ დააწკაპე, მერე space ← →

ორიენტირებული გრაფი · შუალედური წვეროები ≤ 0

-2432-11234

უმოკლეს მანძილთა მატრიცა

i\\j1234
10∞-2∞
2403∞
3∞∞02
4∞-1∞0
ფლოიდ-ვორშელი ერთდროულად ითვლის უმოკლეს გზებს ყველა წყვილს შორის. ვიწყებთ მხოლოდ პირდაპირი წიბოებით; ∞ ნიშნავს „ჯერ გზა არ არის“.

ფსევდოკოდი

 1 d[i][j] = edge weight, ∞ if none, 0 on the diagonal 2 for k in 1..V:   // allow k as an intermediate vertex 3   for all i,j: d[i][j] = min(d[i][j], d[i][k] + d[k][j]) 4 // d now holds all-pairs shortest paths
1 / 1
03

შეამოწმე

სამი კითხვა. აირჩიე პასუხი და ნახე ახსნა.

№1

რატომ უნდა იყოს k გარე ციკლი?

№2

ფლოიდ-ვორშელის შემდეგ d[3][3] = −2. რას ნიშნავს ეს?

№3

V = 2000 წვერო, E = 5000 არაუარყოფითი წიბო, და ყველა წყვილი გჭირდება. რა სჯობს?

04

ივარჯიშე

რეალური ამოცანები გასამყარებლად, მარტივიდან რთულისკენ.