Biri bana Dijkstra'nın neden tek kaynaklı en kısa yol algoritmasının kenarların negatif olmaması gerektiğini varsaydığını söyleyebilir mi?
Negatif ağırlık döngülerinden değil, sadece kenarlardan bahsediyorum.
Biri bana Dijkstra'nın neden tek kaynaklı en kısa yol algoritmasının kenarların negatif olmaması gerektiğini varsaydığını söyleyebilir mi?
Negatif ağırlık döngülerinden değil, sadece kenarlardan bahsediyorum.
Yanıtlar:
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.
A->B
5 A->C
olacak, 2 B->C
olacak -5
. Sonra olacak . Yani değeri bellman-ford C
ile -5
aynı olacaktır . Bu nasıl doğru cevabı vermiyor?
A
0 değeriyle düğümü "kapatacak" . Ardından, minimum değerli düğüme bakacak B
, 5 ve C
2'dir. En küçük C
, bu nedenle C
değer 2 ile kapanacak ve asla geriye bakmayacaktır. daha sonra B
kapatılırsa, C
zaten "kapalı" olduğundan değerini değiştiremez .
A -> B -> C
nasıl bulamaz ? Önce C
mesafesini 2'ye, sonra B
uzaklığını 5'e güncelleyecektir. Grafiğinizde giden kenarların olmadığını varsayarsak, C
ziyaret ederken hiçbir şey yapmayız C
(ve mesafesi hala 2'dir). Sonra D
komşu düğümleri ziyaret ederiz ve komşu düğüm C
yeni 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ı B
ve ardından A
doğru bir sonuçla sonuçlanacağını unutmayın. Neyi kaçırıyorum?
Açıklamamda Dijkstra'nın algoritmasına atıfta bulunduğumda, aşağıda uygulanan Dijkstra Algoritmasından bahsedeceğim,
Dolayısıyla, başlangıçta her bir tepe noktasına atanan değerleri ( kaynaktan tepe noktasına olan mesafe) başlayarak ,
Ö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,
Şimdi C'yi (2 <5), şimdi Q = [B] olarak çıkarıyoruz . C'nin hiçbir şeye bağlı olmadığını, bu nedenle line16
döngü çalışmadığını unutmayın.
Sonunda B'yi çıkarıyoruz, ardından . 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
,
Böylece mesafelerle sonuçlanırız
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 .
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 line16
dö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 line16
hepsi komşu kontrol v (örneğin, yönlendirilmiş bir kenar ile ilgili mevcut u v ) 'in u olan Q yine . Gelen line14
eğer S. So ziyaret edilen notlar kaldırmak x bir ziyaret komşudur u , yol almaktadı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 mevcut en kısa yolu değ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 daha 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.
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.
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.
A
Neler olduğunu görmek için kaynak düğüm olduğunu varsayarak , aşağıdaki grafikte Dijkstra'nın algoritmasını deneyin :
A->B
irade 1
ve A->C
irade 100
. O zaman B->D
olacak 2
. O zaman C->D
olacak -4900
. Yani değeri bellman-ford D
ile -4900
aynı olacaktır . Bu nasıl doğru cevabı vermiyor?
A->B
olacak 1
ve A->C
olacak 100
. Sonra B
araştırdı ve setler edilir B->D
iç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->D
idi 100
, C
ilk araştırdı oldum ki? İnsanların sizinki dışında verdiği diğer tüm örnekleri anlıyorum.
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.
Ş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.
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 .