Belirli düğümleri ziyaret eden bir grafikte en kısa yolu bulun


84

Yaklaşık 100 düğümü ve yaklaşık 200 kenarı olan yönsüz bir grafiğim var. Bir düğüm 'başlangıç', biri 'bitiş' ve yaklaşık bir düzine 'zorunluluk' etiketli.

"Başlangıç" ta başlayan, "bitiş" de biten ve tüm "zorunluluk" düğümlerinden (herhangi bir sırayla) geçen bu grafikte en kısa yolu bulmam gerekiyor .

( http://3e.org/local/maize-graph.png / http://3e.org/local/maize-graph.dot.txt söz konusu grafiktir - Lancaster, PA'da bir mısır labirentini temsil eder)

Yanıtlar:


78

Bunu Seyahat Eden Satıcı Sorunu ile karşılaştıran diğer herkes muhtemelen sorunuzu dikkatlice okumamıştır. TSP'de amaç, tüm köşeleri ziyaret eden en kısa döngüyü bulmaktır (bir Hamilton döngüsü) - bu, her düğümün "zorunluluk" olarak etiketlenmesine karşılık gelir .

Sizin durumunuzda, yalnızca bir düzine 'zorunluluk' olarak etiketlenmiş ve bu 12 verilmiş! oldukça küçüktür (479001600), sadece 'zorunlu geçiş' düğümlerinin tüm permütasyonlarını deneyebilir ve bu sırayla 'zorunlu geçiş' düğümlerini ziyaret eden 'başlangıçtan' sona 'en kısa yola bakabilirsiniz - basitçe bu listedeki her iki ardışık düğüm arasındaki en kısa yolların birleştirilmesi.

Başka bir deyişle, önce her bir köşe çifti arasındaki en kısa mesafeyi bulun (Dijkstra'nın algoritmasını veya diğerlerini kullanabilirsiniz, ancak bu küçük sayılarla (100 düğüm), kodlaması en basit Floyd-Warshall algoritması bile zamanında çalışacaktır). Sonra, bunu bir tabloya koyduğunuzda, 'zorunlu geçiş' düğümlerinizin tüm permütasyonlarını ve geri kalanını deneyin.

Bunun gibi bir şey:

//Precomputation: Find all pairs shortest paths, e.g. using Floyd-Warshall
n = number of nodes
for i=1 to n: for j=1 to n: d[i][j]=INF
for k=1 to n:
    for i=1 to n:
        for j=1 to n:
            d[i][j] = min(d[i][j], d[i][k] + d[k][j])
//That *really* gives the shortest distance between every pair of nodes! :-)

//Now try all permutations
shortest = INF
for each permutation a[1],a[2],...a[k] of the 'mustpass' nodes:
    shortest = min(shortest, d['start'][a[1]]+d[a[1]][a[2]]+...+d[a[k]]['end'])
print shortest

(Tabii ki bu gerçek kod değil ve gerçek yolu istiyorsanız, hangi permütasyonun en kısa mesafeyi verdiğini ve ayrıca tüm çiftlerin en kısa yollarının ne olduğunu takip etmeniz gerekir, ancak fikri anladınız.

Herhangi bir makul dilde en fazla birkaç saniye içinde çalışacaktır :)
[Düğümleriniz ve k 'zorunluluk' düğümleriniz varsa, çalışma süresi Floyd-Warshall bölümü için O (n 3 ) ve O (k! N ) tüm permütasyonlar bölümü için ve gerçekten kısıtlayıcı kısıtlamalarınız yoksa 100 ^ 3 + (12!) (100) pratik olarak fıstıktır.]


7
Küçük giriş boyutu göz önüne alındığında, cevaba katılıyorum. Ama başkalarının bunun bir TSP vakası olduğuna dair iddialarını neden reddettiğinizle ilgileniyorum. Anladığım kadarıyla, geçirilmesi gereken tüm düğümleri çıkarabilir ve bir alt grafik oluşturmak için kullanabilirsiniz. Alt grafikteki düğümler arasındaki kenarlar, orijinal grafikteki APSP çözümüne karşılık gelen ağırlıklara sahiptir. Öyleyse soru alt grafikte TSP'nin bir örneği olmaz mı? Çözümünüz, bu soruna kaba kuvvetli bir çözüm gibi görünüyor (ki bu iyi).
maditya

7
@maditya: Öncelikle, "TSP zordur, bwahahaha" gibi bir cevabın (Steven A Lowe'un başka bir cevaba ilişkin yorumundan alıntı yapacak olursak) gerçek bir sorunu olan biri için, özellikle de çok kolay bir şekilde çözülmesi gereken bir cevap olmadığını kabul ettiğinizi umuyorum. son birkaç on yılda herhangi bir bilgisayarda çözüldü. İkinci olarak, önemsiz nedenlerden dolayı bu TSP ile aynı değildir (farklı giriş formatı): İçerdiği küçük TSP örneği, giriş boyutu N için değil, daha küçük bir grafik içindir. Dolayısıyla, NP-tamlığı, kaç 'zorunlu geçiş' düğümüne bağlıdır. asimptotik olarak vardır: eğer her zaman 12 ise veya O (log N) ise, NP-tamamlanmamış vb.
ShreevatsaR

1
Sonucun bir yol olup olmayacağından emin değilim. Gitmek zorunda düşünün aiçin cadım açıklamalı b. Bir kenara bgiden ave cpaylaşan en kısa yollar olabilir . Bu durumda kenar iki kez tekrarlanacaktır. Döngü oluşturmamak için iki yoldan birinin optimumdan daha kötü olması gerekir.
Spak

1
@PietroSaccardi Sorudaki açıklamadan, amaç basitçe tüm bu düğümlerden geçmenin en kısa "yolunu" bulmak gibi görünüyor ve bazı sınırlar tekrarlanırsa sorun olmayabilir. Yani “yol” gevşek anlamda kullanılıyor. Aslında, tekrarlanan kenarlara izin verilmezse, bir cevap bile olmayabilir (örneğin, B'den geçerken A'dan C'ye gitmenizin istendiği bir B — A — C grafiğini düşünün: B — Bir kenar).
ShreevatsaR

Floyd-Warshall algoritması burada doğru bir şekilde uygulanmamıştır: dizinin tüm hücreleri ile başlatıldığından INF, çizgi d[i][j] = min(d[i][j], d[i][k] + d[k][j])olur d[i][j] = min(INF, INF + INF)ve tüm hücreler her zaman eşit kalır INF. Bu diziyi grafikteki kenar uzunluklarıyla doldurmak için bir adım eklemeniz gerekir.
Stef

25

Tüm kritik düğümler (başlangıç, bitiş ve geçilmesi gereken) arasındaki en kısa yolları bulmak için Djikstra Algoritmasını çalıştırın , ardından bir derinlik ilk geçişi, tüm düğümlerin başlangıcına dokunan sonuçtaki alt grafik boyunca en kısa yolu size söylemelidir. . zorunluluklar ... son


Bu, seçilen çözümden daha verimli olma potansiyeline sahip gibi görünüyor. Bahse girerim, biraz daha fazla etmeliysen daha yüksek puan alırdı. İlk önce, tüm çiftler arasındaki en kısa yolun gerekli tüm düğümler arasında bir yolu garanti edip etmediğini düşünmek zorundaydım .. ama bunun olacağını düşünüyorum (yönlendirilmediğini varsayarak).
galactikuh

Bir yolun kenarları tekrar etmemesi gerekiyorsa bunun işe yaramayacağını düşünüyorum.
tuket

1
İlk derinlik geçişi Kodun Advent günü 24 örneğinde en kısa yolu nasıl bulur? adventofcode.com/2016/day/24
Erwin Rooijakkers

17

Bu iki sorun ... Steven Lowe buna işaret etti, ancak sorunun ikinci yarısına yeterince saygı göstermedi.

Öncelikle tüm kritik düğümleriniz arasındaki en kısa yolları keşfetmelisiniz (başlangıç, bitiş, zorunluluk). Bu yollar keşfedildikten sonra, yeni grafikteki her kenarın orijinal grafikteki bir kritik düğümden diğerine giden bir yol olduğu basitleştirilmiş bir grafik oluşturabilirsiniz. Burada en kısa yolu bulmak için kullanabileceğiniz birçok yol bulma algoritması vardır.

Yine de bu yeni grafiğe sahip olduğunuzda, tam olarak Seyahat Eden Satış Görevlisi probleminiz var (yani, neredeyse ... Başlangıç ​​noktanıza dönmenize gerek yok). Bununla ilgili yukarıda bahsedilen herhangi bir gönderi geçerli olacaktır.


14

Aslında, gönderdiğiniz problem seyahat eden satıcıya benziyor, ancak basit bir yol bulma problemine daha yakın olduğunu düşünüyorum. Her bir düğümü ziyaret etmeniz gerekmektense, mümkün olan en kısa sürede (mesafe) belirli bir düğüm kümesini ziyaret etmeniz yeterlidir.

Bunun nedeni, gezgin satıcı sorununun aksine, bir mısır labirentinin, oraya ulaşmak için başka düğümlerden geçmenize gerek kalmadan, haritadaki herhangi bir noktadan başka herhangi bir noktaya doğrudan seyahat etmenize izin vermemesidir.

Aslında dikkate alınması gereken bir teknik olarak A * yol bulmayı tavsiye ederim. Bunu, hangi düğümlerin hangi diğer düğümlere doğrudan erişebileceğine ve belirli bir düğümden her bir atlamanın "maliyetinin" ne olduğuna karar vererek ayarlarsınız. Bu durumda, düğümleriniz görece yakın aralıklı göründüğünden, her "atlama" eşit maliyetli olabilir. A *, herhangi iki nokta arasındaki en düşük maliyetli yolu bulmak için bu bilgiyi kullanabilir. A noktasından B noktasına gitmeniz ve aralarında yaklaşık 12 kişiyi ziyaret etmeniz gerektiğinden, yol bulmayı kullanan kaba kuvvet yaklaşımı bile hiç zarar vermez.

Dikkate alınması gereken bir alternatif. Bu görünüm yapar derece seyyar satıcı sorunu gibi ve bu kadar okumak, ama daha yakından bakmak için iyi kağıtlar ve onun sadece overcomplicating şeylerin olduğunu göreceksiniz. ^ _ ^ Bu, daha önce bu tür şeylerle ilgilenmiş bir video oyun programcısının aklından geliyor.


2
+1 - bu, 'saleman sorunu zor, bwahahaha'dan çok daha iyi bir cevap
Steven

6

Andrew Top'un doğru fikri var:

1) Djikstra Algoritması 2) Bazı TSP sezgisel yöntemleri.

Lin-Kernighan buluşsal yöntemini öneririm: Herhangi bir NP Complete problemi için en iyi bilinenlerden biridir. Unutulmaması gereken tek şey, 2. adımdan sonra grafiği tekrar genişlettikten sonra, genişletilmiş yolunuzda döngüler olabilir, bu nedenle bunları kısa devre yaptırmanız gerekir (yolunuz boyunca köşelerin derecesine bakın).

Aslında bu çözümün optimuma göre ne kadar iyi olacağından emin değilim. Muhtemelen kısa devre ile ilgili bazı patolojik durumlar vardır. Sonuçta, bu problem ÇOK Steiner Tree gibi görünüyor: http://en.wikipedia.org/wiki/Steiner_tree ve Steiner Tree'ye sadece grafiğinizi daraltarak ve örneğin Kruskal'ı çalıştırarak kesinlikle kestiremezsiniz.


6

Bu değil orijinal soru düğümleri sadece bir kez ziyaret olduğunu mutlaka geçmek gerektirmediğinden TSP sorunu ve NP-zor değil. Bu, Dijkstra'nın algoritması aracılığıyla tüm geçilmesi gereken düğümler arasındaki en kısa yolların bir listesini derledikten sonra yanıtı sadece kaba kuvvetten çok daha basit hale getirir. Gitmenin daha iyi bir yolu olabilir, ancak basit bir yol, ikili bir ağacı geriye doğru çalışmaktır. Bir düğüm listesi düşünün [başlangıç, a, b, c, bitiş]. Basit mesafeleri toplayın [start-> a-> b-> c-> end] bu, geçmeniz gereken yeni hedef mesafenizdir. Şimdi [start-> a-> c-> b-> end] deneyin ve bu hedef olarak daha iyi ayarlanırsa (ve bunun düğümlerin bu modelinden geldiğini unutmayın). Permütasyonlar üzerinde geriye doğru çalışın:

  • [başlangıç-> a-> b-> c-> bitiş]
  • [başlangıç-> a-> c-> b-> bitiş]
  • [başlangıç-> b-> a-> c-> bitiş]
  • [başlangıç-> b-> c-> a-> bitiş]
  • [başlangıç-> c-> a-> b-> bitiş]
  • [başlangıç-> c-> b-> a-> bitiş]

Bunlardan biri en kısa olacak.

(Varsa 'birden çok kez ziyaret edilen' düğümler nerede? En kısa yol başlatma adımında gizlidirler. a ve b arasındaki en kısa yol c veya hatta bitiş noktası içerebilir. Önem vermenize gerek yok )


En kısa yol olması şartıyla yalnızca bir kez ziyaret edilmesi zorunludur.
Aziuth

Huh. Bir dakika önce oldukça emindim, ama evet, haklısın. Belli ki birkaç dalı olan bir ağaçta değil. Ancak problemi, orijinal grafikteki en kısa yol mesafesine sahip düğümlerle tamamen bağlı olan sadece zorunlu geçiş düğümlerini içeren yeni bir grafiğe soyutlarsak, TSP'ye ulaşırız. Öyleyse, NP-zor olmadığından emin misin? Genel problemde, zorunluluk düğümlerinin miktarının toplam düğüm miktarına bağlı olduğunu ve örneğin toplam, zorunlu geçişin bir polinomiyse, NP sertliğini elde ettiğimizi varsayıyorum, değil mi?
Aziuth

Örneğin a-> b'den gelen yol c'den geçebilir. Yani hiçbir brnach diğerini engellemez. Bu sadece permütasyon.
bjorke

Evet? Ancak, zorunlu geçiş düğümlerinin miktarının, "toplam düğümler, zorunlu geçiş düğümlerinin bir polinomudur" gibi, toplam düğüm miktarıyla bir miktar bağlantısı olduğunu varsayarsak, permütasyon O (n!) Olur. TSP'yi kaba kuvvetle çözdün.
Aziuth

2

Düğümlerin ve kenarların miktarının göreceli olarak sınırlı olduğunu düşünürsek, muhtemelen her yolu hesaplayabilir ve en kısa yolu seçebilirsin.

Genellikle bu, seyahat eden satıcı problemi olarak bilinir ve hangi algoritmayı kullanırsanız kullanın, deterministik olmayan bir polinom çalışma süresine sahiptir.

http://en.wikipedia.org/wiki/Traveling_salesman_problem


1

Soru , HERHANGİ bir sırayla geçilmesi gerekenlerden bahsediyor . Geçilmesi gereken düğümlerin tanımlanmış sırası hakkında bir çözüm aramaya çalışıyordum. Cevabımı buldum, ancak StackOverflow'da hiçbir soru benzer bir soru içermediğinden, maksimum insanın bundan yararlanmasını sağlamak için buraya gönderiyorum.

Sıra veya geçirilmesi gereken tanım tanımlanmışsa , dijkstra algoritmasını birden çok kez çalıştırabilirsiniz. Örneğin izin için Diyelim ki başlamak zorunda varsayalım sgeçitten k1, k2ve k3de (Sırasıyla) ve durdurma e. O zaman yapabileceğiniz şey, dijkstra algoritmasını birbirini izleyen her düğüm çifti arasında çalıştırmaktır. Maliyet ve yol tarafından verilecek:

dijkstras(s, k1) + dijkstras(k1, k2) + dijkstras(k2, k3) + dijkstras(k3, 3)


0

Bir düzine 'ziyaret edilmesi gereken' düğümlerde kaba kuvvet kullanmaya ne dersiniz? 12 düğümün tüm olası kombinasyonlarını yeterince kolayca kapsayabilirsiniz ve bu sizi, onları kapsayacak şekilde takip edebileceğiniz en uygun devre ile bırakır.

Şimdi probleminiz, başlangıç ​​düğümünden devreye en uygun rotaları bulmakla basitleştirildi, daha sonra bunları kaplayana kadar takip edin ve sonra ondan sonuna kadar rotayı bulun.

Nihai yol şunlardan oluşur:

başlangıç ​​-> devreye giden yol * -> düğümleri ziyaret etmelidir devresi -> sona giden yol * -> bitiş

* İle işaretlediğim yolları böyle buluyorsun

Başlangıç ​​düğümünden devredeki her noktaya bir A * araması yapın, bunların her biri için devrede sonraki ve önceki düğümden sonuna kadar bir A * araması yapın (çünkü devreyi her iki yönde de takip edebilirsiniz) Sonuçta çok sayıda arama yolu vardır ve en düşük maliyetli olanı seçebilirsiniz.

Aramaları önbelleğe alarak optimizasyon için çok yer var, ancak bunun iyi çözümler üreteceğini düşünüyorum.

Yine de en uygun çözümü aramaya yakın bir yere gitmez, çünkü bu, aramada mutlaka ziyaret edilmesi gereken devrenin bırakılmasını içerebilir.


0

Hiçbir yerde belirtilmeyen bir şey, aynı tepe noktasının yolda birden fazla ziyaret edilmesinin uygun olup olmadığıdır. Buradaki yanıtların çoğu, aynı kenarı birden çok kez ziyaret etmenin uygun olduğunu varsayar, ancak soruyu veriyorum (bir yol aynı tepe noktasını birden fazla ziyaret etmemelidir!), Aynı tepe noktasını iki kez ziyaret etmenin uygun olmadığıdır .

Dolayısıyla kaba kuvvet yaklaşımı yine de geçerli olacaktır, ancak yolun her bir alt kümesini hesaplamaya çalıştığınızda zaten kullanılmış olan köşeleri kaldırmanız gerekir.

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.