Dijkstra'nın algoritması neden negatif ağırlık kenarları için çalışmıyor?


Yanıtlar:


175

Dijkstra'nın algoritmasında, bir köşe "kapalı" (ve açık küme dışında) olarak işaretlendiğinde - algoritmanın ona giden en kısa yolu bulduğunu ve bu düğümü bir daha asla geliştirmek zorunda kalmayacağını - bunun için geliştirilen yolu varsaydığını hatırlayın. yol en kısadır.

Ancak negatif ağırlıklarla - bu doğru olmayabilir. Örneğin:

       A
      / \
     /   \
    /     \
   5       2
  /         \
  B--(-10)-->C

V={A,B,C} ; E = {(A,C,2), (A,B,5), (B,C,-10)}

A'dan Dijkstra önce C'yi geliştirecek ve daha sonra bulamayacak A->B->C


Biraz daha derin açıklamayı DÜZENLE :

Bunun önemli olduğuna dikkat edin, çünkü her gevşetme adımında, algoritma "kapalı" düğümlere "maliyet" in gerçekten minimum olduğunu varsayar ve bu nedenle bir sonraki seçilecek düğüm de minimumdur.

Bunun fikri şudur: Maliyeti minimum olacak şekilde açık bir tepe noktasına sahipsek - herhangi bir tepe noktasına herhangi bir pozitif sayı ekleyerek - minimumluk asla değişmeyecektir.
Pozitif sayılar üzerinde kısıtlama olmadan - yukarıdaki varsayım doğru değildir.

"Kapalı" olan her bir tepe noktasını "bildiğimiz" için - "geriye bakmadan" gevşeme adımını güvenli bir şekilde yapabiliriz. "Geriye bakmamız" gerekirse - Bellman-Ford bunu yapmak için özyinelemeli (DP) benzeri bir çözüm sunar.


5
Üzgünüm ama herhangi bir hata alamıyorum. Önce A->B5 A->Colacak, 2 B->Colacak -5. Sonra olacak . Yani değeri bellman-ford Cile -5aynı olacaktır . Bu nasıl doğru cevabı vermiyor?
Anirban Nag 'tintinmj'

5
@tintinmj önce, Dijkstra A0 değeriyle düğümü "kapatacak" . Ardından, minimum değerli düğüme bakacak B, 5 ve C2'dir. En küçük C, bu nedenle Cdeğer 2 ile kapanacak ve asla geriye bakmayacaktır. daha sonra Bkapatılırsa, Czaten "kapalı" olduğundan değerini değiştiremez .
amit

4
@amit Dijkstra'nın algoritması yolu A -> B -> Cnasıl bulamaz ? Önce Cmesafesini 2'ye, sonra Buzaklığını 5'e güncelleyecektir. Grafiğinizde giden kenarların olmadığını varsayarsak, Cziyaret ederken hiçbir şey yapmayız C(ve mesafesi hala 2'dir). Sonra Dkomşu düğümleri ziyaret ederiz ve komşu düğüm Cyeni mesafesi -5 olan tek düğümdür . Dijkstra algoritmasında, düğüme ulaştığımız (ve güncellediğimiz) ebeveyni de takip ettiğimizi ve bunu yaptığımızda C, ebeveyni alacağınızı Bve ardından Adoğru bir sonuçla sonuçlanacağını unutmayın. Neyi kaçırıyorum?
nbro

12
@amit Muhakemenizdeki problem (sanırım) ve bunu yapan diğer insanları gördüm (tuhaf bir şekilde), algoritmanın en kısa mesafesi önceden belirlenmiş (ve bizim işimiz bitti) düğümleri yeniden düşünmeyeceğini düşünmeniz, ancak bu doğru değil ve bu yüzden "gevşeme" adımına sahibiz ... Grafiğin tüm düğümlerini yineliyoruz ve her biri için, bitişik düğümlerden herhangi biri olsa bile, bitişik düğümlerde yineliyoruz. örneğin, minimum öncelik sıramızdan zaten kaldırıldı.
nbro

10
@amit Bu yanıtı, örneğin gerçekten mantıklı olduğu benzer bir soruya kontrol edin: stackoverflow.com/a/6799344/3924118
nbro

37

Kaynakla aşağıda gösterilen grafiği Vertex A olarak düşünün. Önce Dijkstra algoritmasını üzerinde kendiniz çalıştırmayı deneyin.

görüntü açıklamasını buraya girin

Açıklamamda Dijkstra'nın algoritmasına atıfta bulunduğumda, aşağıda uygulanan Dijkstra Algoritmasından bahsedeceğim,

Dijkstra algoritması

Dolayısıyla, başlangıçta her bir tepe noktasına atanan değerleri ( kaynaktan tepe noktasına olan mesafe) başlayarak ,

başlatma

Önce Q = [A, B, C] 'deki en küçük değere sahip olan tepe noktasını çıkarıyoruz , yani A, ardından Q = [B, C] . Not A'nın B ve C'ye yönelik bir kenarı vardır, ayrıca ikisi de Q'dadır, bu nedenle bu iki değeri de güncelliyoruz,

ilk yineleme

Şimdi C'yi (2 <5), şimdi Q = [B] olarak çıkarıyoruz . C'nin hiçbir şeye bağlı olmadığını, bu nedenle line16döngü çalışmadığını unutmayın.

ikinci yineleme

Sonunda B'yi çıkarıyoruz, ardından Q, Phi'dir. Not B'nin C'ye yönelik bir kenarı vardır, ancak C, Q'da mevcut değildir, bu nedenle tekrar for döngüsüne girmeyiz line16,

3 üncü?

Böylece mesafelerle sonuçlanırız

değişiklik yok arkadaşlar

Gittiğinizde A'dan C'ye en kısa mesafe 5 + -10 = -5 olduğu için bunun ne kadar yanlış olduğuna dikkat edin a'dan c'ye.

Yani bu grafik için Dijkstra Algoritması yanlış bir şekilde A'dan C'ye olan mesafeyi hesaplıyor.

Bunun nedeni, Dijkstra Algoritmasının Q'dan çıkarılmış olan köşelere daha kısa bir yol bulmaya çalışmamasıdır .

Ne line16döngü yapıyor Vertex alarak u ve diyerek biz gidebilirsiniz gibi "hey görünüyor v aracılığıyla kaynağından u , daha iyi akım daha ki (alt veya alternatif) mesafedir [v] dist güncellemeyi izin verirse biz? Got dist [v] "

Bu Not line16hepsi komşu kontrol v (örneğin, yönlendirilmiş bir kenar ile ilgili mevcut u v ) 'in u olan Q yine . Gelen line14eğer S. So ziyaret edilen notlar kaldırmak x bir ziyaret komşudur u , yol u'dan x'e kaynakalmaktadır bile sayılmaz kaynaktan olası bir kısa yol olarak v .

Yukarıdaki örneğimizde, C, B'nin ziyaret edilen bir komşusuydu, bu nedenle A'dan B'ye Cmevcut en kısa yolu A'dan C'yedeğiştirmeden bırakarak yol dikkate alınmadı .

Kenar ağırlıklarının tümü pozitif sayılarsa bu gerçekten yararlıdır , çünkü o zaman daha kısa olamayacak yolları düşünerek zamanımızı boşa harcamayız .

Bu yüzden, bu algoritmayı çalıştırırken , eğer x Q'dan y'den önce çıkarılırsa , o zaman mümkün değildaha kısa olan bir yol bulmanın mümkün olmadığını söylüyorum . Bunu bir örnekle açıklayayım,

Olarak y sadece ekstre edilmiş ve x tek başına önce, daha sonra ekstre edilmiştir dist [y]> dist [x] ' çünkü aksi takdirde Y daha önce ekstre olurdu x . ( line 13önce minimum mesafe)

Ve zaten kenar ağırlıklarının pozitif olduğunu varsaydığımız gibi , yani uzunluk (x, y)> 0 . Dolayısıyla, y yoluyla alternatif mesafe (alt) her zaman daha büyük olacaktır, yani dist [y] + uzunluk (x, y)> dist [x] . Dolayısıyla, y , x'e giden bir yol olarak kabul edilse bile dist [x] ' in değeri güncellenmezdi , bu nedenle, y'nin yalnızca hala Q'da olan komşularını dikkate almanın mantıklı olduğu sonucuna vardık (not yorumu içinde )line16

Fakat bu şey, pozitif kenar uzunluğu varsayımımıza dayanır, eğer uzunluk (u, v) <0 ise, o zaman kenarın ne kadar negatif olduğuna bağlı olarak , karşılaştırmadan sonra dist [x] 'i değiştirebiliriz line18.

Bu nedenle herhangi bir dist [x] eğer yanlış olacaktır yapmak hesaplama x bütün çıkıntılar önce çıkarılır v - bu şekilde X bir komşu v negatif kenar bağlamadan ile - uzaklaştırılır.

Çünkü bu v köşelerinden her biri, Dijkstra algoritması tarafından atılan kaynaktan x'e potansiyel "daha iyi" bir yol üzerindeki ikinci son köşe noktasıdır.

Yani yukarıda verdiğim örnekte hata, B kaldırılmadan önce C'nin kaldırılmasıydı. C, B'nin negatif kenarı olan bir komşusuyken!

Sadece açıklığa kavuşturmak için, B ve C, A'nın komşularıdır. B'nin tek bir komşusu C vardır ve C'nin komşusu yoktur. uzunluk (a, b), a ve b köşeleri arasındaki kenar uzunluğudur.


2
Söylediğiniz gibi, bunu çözmenin daha iyi yolu her karşılaştırmadan sonra heapq.heappush yöntemini kullanmaktır. Güncellenen mesafeyi kuyruğa geri çekiyoruz. Bu şartlar altında Dijkstra'lar negatif ağırlıklarda çalışabilir. Denedim ve sonuç 0,5, -5 olarak çıktı
2017

1
"x'den u'ya giden yol kaynağı dikkate alınmaz bile"; u'dan x'e kaynak mı demek istedin?
slmatrix

1
@slmatrix bunu yakaladığın için teşekkürler, evet, kaynaktan u'ya giden yolu kastetmiştim, çünkü x, u'nun komşusu.
Aditya P

23

Dijkstra'nın algoritması, yolların yalnızca 'daha ağır' hale gelebileceğini varsayar, böylece A'dan B'ye 3'lük bir yolunuz ve A'dan C'ye 3'lük bir yolunuz varsa, bir kenar ve A'dan B'ye, 3'ten az ağırlık ile C'ye gidin.

Bu varsayım, algoritmayı negatif ağırlıkları hesaba katması gereken algoritmalardan daha hızlı yapar.


8

Dijkstra algoritmasının doğruluğu:

Algoritmanın herhangi bir adımında 2 set köşemiz var. Set A, en kısa yolları hesapladığımız köşelerden oluşur. Set B, kalan köşelerden oluşur.

Tümevarımsal Hipotez : Her adımda, önceki tüm yinelemelerin doğru olduğunu varsayacağız.

Endüktif Adım : A kümesine bir tepe noktası V eklediğimizde ve mesafeyi mesafeyi [V] olarak ayarladığımızda, bu mesafenin optimal olduğunu kanıtlamalıyız. Bu optimal değilse, o zaman V tepe noktasına daha kısa uzunlukta başka bir yol olmalıdır.

Bunun başka bir yolun bir X tepe noktasından geçtiğini varsayalım.

Şimdi, dist [V] <= dist [X] olduğundan, bu nedenle V'ye giden diğer herhangi bir yol, grafiğin negatif kenar uzunluklarına sahip olmadığı sürece, en az dist [V] uzunluğunda olacaktır.

Bu nedenle dijkstra algoritmasının çalışması için kenar ağırlıklarının negatif olmaması gerekir.


6

ANeler olduğunu görmek için kaynak düğüm olduğunu varsayarak , aşağıdaki grafikte Dijkstra'nın algoritmasını deneyin :

grafik


6
Üzgünüm ama herhangi bir hata alamıyorum. İlk A->Birade 1ve A->Cirade 100. O zaman B->Dolacak 2. O zaman C->Dolacak -4900. Yani değeri bellman-ford Dile -4900aynı olacaktır . Bu nasıl doğru cevabı vermiyor?
Anirban Nag 'tintinmj'

9
@tintinmj Eğer D'den giden bir kenarınız varsa, D'nin mesafesi azalmadan önce ziyaret edilecek ve dolayısıyla dolduktan sonra güncellenmeyecektir. Bu daha sonra kesinlikle bir hataya neden olacaktır. D'nin 2'sini giden kenarları taradıktan sonra zaten son mesafe olarak kabul ederseniz, bu grafik bile bir hatayla sonuçlanır.
Christian Schnorr

@ tb- Bu kadar uzun bir süre sonra sorduğum için özür dilerim ama burada doğru yolda mıyım? İlk A->Bolacak 1ve A->Colacak 100. Sonra Baraştırdı ve setler edilir B->Diçin 2. O halde D araştırılır çünkü şu anda kaynağa giden en kısa yola sahiptir? Ben eğer o söyleyerek doğru olur B->Didi 100, Cilk araştırdı oldum ki? İnsanların sizinki dışında verdiği diğer tüm örnekleri anlıyorum.
Pejman Poh

@PejmanPoh benim anlayışıma göre B-> D 100 ise, kullanılacak HeapStructure'da A-> C daha yüksek olduğu için, ayıklama min önce A-> C'yi döndürecektir, yani bir sonraki bulunan en kısa yol yol olacaktır C'ye kadar, bundan sonra C-> D'den -5000 ağırlığa sahip olan yol bariz bir seçim olacak ve bizi en kısa yolun A-> C-> D'den geleceği sonucuna götürüyor ve bunun olacağından oldukça eminim normal davranış ol. Bu nedenle, bazen negatif döngülerimiz olduğunda, en kısa yol için hala doğru değeri elde edebiliriz, ancak kesinlikle her zaman değil, bu, alamayacağımız bir örnek ..
T.Dimitrov

1

Dijkstra'nın algoritmasında, bir tepe noktası "kapalı" (ve açık küme dışında) olarak işaretlendiğinde - bundan kaynaklanan herhangi bir düğümün daha büyük mesafeye yol açacağını varsayar, bu nedenle algoritma ona giden en kısa yolu bulacaktır ve bu düğümü bir daha asla geliştirmek zorunda kalmazsınız, ancak negatif ağırlıklar söz konusu olduğunda bu geçerli değildir.


0

Şimdiye kadarki diğer cevaplar, Dijkstra algoritmasının yollardaki negatif ağırlıkları neden işleyemediğini oldukça iyi gösteriyor.

Ancak sorunun kendisi, belki de yolların ağırlığının yanlış anlaşılmasına dayanmaktadır. Yol bulma algoritmalarında genel olarak yollarda negatif ağırlıklara izin verilirse, durmayan kalıcı döngüler elde edersiniz.

Bunu düşün:

A  <- 5 ->  B  <- (-1) ->  C <- 5 -> D

A ve D arasındaki en uygun yol nedir?

Herhangi bir yol bulma algoritmasının sürekli olarak B ve C arasında döngü yapması gerekir, çünkü böyle yapmak toplam yolun ağırlığını azaltır. Dolayısıyla, bir bağlantı için negatif ağırlıklara izin vermek, herhangi bir yol bulma algoritmasını tartışmalı hale getirir, belki de her bir bağlantıyı yalnızca bir kez kullanılacak şekilde sınırlamanız dışında.


0

Dijkstra'nın algoritmasını negatif döngü içermeyen negatif kenarlarla kullanabilirsiniz, ancak bir köşenin birden çok kez ziyaret edilebilmesine izin vermelisiniz ve bu sürüm hızlı zaman karmaşıklığını kaybeder.

Bu durumda, pratik olarak normal kuyruğu olan ve negatif kenarları idare edebilen SPFA algoritmasını kullanmanın daha iyi olduğunu gördüm .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.