İlk olarak, bunun neden zor bir sorun olmadığını gösteren küçük bir arka plan . Bir nehirden geçen akış, doğru şekilde dijitalleştirilirse, segmentlerinin her zaman yönlendirilmiş bir asiklik grafik (DAG) oluşturmak üzere yönlendirilebileceğini garanti eder . Buna karşılık, bir grafik, topolojik sıralama olarak bilinen bir teknik kullanılarak sadece ve eğer bir DAG ise doğrusal olarak sıralanabilir . Topolojik sıralama hızlıdır: zaman ve alan gereksinimleri hem O (| E | + | V |) 'dir (E = kenar sayısı, V = köşe sayısı). Böyle doğrusal bir düzen oluşturmak, büyük dere yatağını bulmayı kolaylaştıracaktır.
İşte burada, bir algoritmanın taslağı . Derenin ağzı ana yatağı boyunca uzanır. Ağza bağlı her dal boyunca yukarı doğru hareket edin (ağız bir konflunsa sahipse birden fazla olabilir) ve dalına giden ana yatağı tekrar tekrar bulun. Toplam uzunluğun en büyük olduğu dalı seçin: ana yatak boyunca "geri bağlantınız" budur.
Bunu daha net hale getirmek için, bazı (test edilmemiş) sahte kod teklif ediyorum . Giriş , her biri iki ayrı uç nokta başlangıç (S) ve uç (S) ve pozitif bir uzunluk, uzunluk (S) olan bir dizi çizgi parçası (veya yay) S'dir (sayısallaştırılmış akışı içerir ); ve bir nokta olan nehir ağzı p . Çıktı, ağzı en uzak yukarı akış noktasıyla birleştiren bir segment dizisidir.
"İşaretli segmentler" (S, p) ile çalışmamız gerekecek. Bunlar, S segmentlerinden biriyle birlikte iki uç noktasından birinden oluşur, s . Prob noktası q ile bir uç noktayı paylaşan , bu segmentleri diğer uç noktalarıyla işaretleyen ve seti döndüren S segmentlerini bulmamız gerekecek :
Procedure Extract(q: point, A: set of segments): Set of marked segments.
Böyle bir segment bulunamadığında, Ayıkla boş kümeyi döndürmelidir. Bir yan etki olarak, Ekstrakt A setinden döndüğü tüm segmentleri kaldırmalı , böylece A'nın kendisini değiştirmelidir .
Extract uygulaması vermiyorum: CBS'niz q ile bir uç noktayı paylaşan S segmentlerini seçebilmenizi sağlayacaktır . Bunları işaretlemek, hem başlangıç (S) hem de bitiş (S) 'yi q ile karşılaştırmak ve iki uç noktadan hangisinin eşleşmediğini döndürmektir.
Şimdi sorunu çözmeye hazırız.
Procedure LongestUpstreamReach(p: point, A: set of segments): (Array of segments, length)
A0 = A // Optional: preserves A
C = Extract(p, A0) // Removes found segments from the set A0!
L = 0; B = empty array
For each (S,q) in C: // Loop over the segments meeting point p
(B0, M) = LongestUpstreamReach(q, A0)
If (length(S) + M > L) then
B = append(S, B0)
L = length(S) + M
End if
End for
Return (B, L)
End LongestUpstreamReach
Prosedür "Ekleme (S B0)" çubukları kademeli S dizi sonunda B0 ve yeni bir dizi döner.
(Akım gerçekten bir ağaç ise: hayır adalar, göller, örgü, vb - o zaman kopyalama aşaması uygulamasından vazgeçilmesi olabilir A içine A0 .)
Orijinal soru, LongestUpstreamReach tarafından döndürülen segmentlerin birleşimi oluşturularak cevaplanır.
Açıklamak için orijinal haritadaki akışı ele alalım. Varsayalım ki yedi yay koleksiyonu olarak dijitalleştirildi. Ark a , nokta 1'deki ilk izdihamın akış yukarısında, 0 noktasından (haritanın üst kısmı, aşağıdaki şekilde sağa döndürülür) ağızdan gider. 8 birim uzunluğunda uzun bir yay. Ark b sola (haritada) dallanır ve kısa, yaklaşık 2 birim uzunluğundadır. Ark c sağa doğru dallar ve yaklaşık 4 birim uzunluğundadır, vb. "B", "d" ve "f" harfleri, haritanın yukarıdan aşağıya doğru gittikçe sol taraftaki dalları ve "a" yı gösterirken, "c", "e" ve diğer dalları "g" ve 0'dan 7'ye kadar olan köşeleri numaralandırarak, grafiği soyut olarak yay koleksiyonu olarak gösterebiliriz
A = {a=(0,1), b=(1,2), c=(1,3), d=(3,4), e=(3,5), f=(5,6), g=(5,7)}
Onlar uzunlukları 8, 2, 4, 1, 2, için 2, 2 olduğunu varsayalım olacak bir içinden g , sırasıyla. Ağız köşe 0'dır.
İlk örnek, Çıkar (5, {f, g}) çağrısıdır. İşaretli segment kümesini {(f, 6), (g, 7)} döndürür. Köşe 5'in f ve g yaylarının (haritanın altındaki iki yay) birleştiği ve (f, 6) ve (g, 7) bu yayların her birini yukarı akış uç noktalarıyla işaretlediğine dikkat edin.
Bir sonraki örnek LongestUpstreamReach (0, A) çağrısıdır. Yaptığı ilk eylem, Çıkar (0, A) çağrısıdır. Bu döner belirgin bir bölümü (a, 1) ihtiva eden bir dizi ve bunun kademeli kaldırır a kümesinden A0 artık {b, c, d, e, f, g} eşittir. Döngünün bir tekrarı vardır, burada (S, q) = (a, 1). Bu yineleme sırasında LongestUpstreamReach (1, A0) çağrısı yapılır. Yinelemeli olarak, (g, e, c) veya (f, e, c) dizisini döndürmelidir: her ikisi de eşit derecede geçerlidir. Uzunluk (M) ya da döner 4 + 2 + = 8. 2 (Not LongestUpstreamReach yapmasıdır değildir ve değişiklikler A0 .) Döngü sonunda, kademeli birakış yatağına eklenmiştir ve uzunluk 8 + 8 = 16'ya çıkarılmıştır. Dolayısıyla, ilk geri dönüş değeri (g, e, c, a) veya (f, e, c, a) dizisinden oluşur, ikinci dönüş değeri için her iki durumda da 16 uzunluğundadır. Bu, LongestUpstreamReach'in ağızdan nasıl yukarı doğru hareket ettiğini gösterir, her bir konfluyonda henüz gidilecek en uzun mesafeye sahip dalı seçer ve rotası boyunca çapraz olan segmentleri takip eder.
Birçok örgüler ve adalar olduğunda daha verimli bir uygulama mümkündür, ancak çoğu amaç için LongestUpstreamReach tam olarak gösterildiği gibi uygulanırsa çok az harcanan çaba olacaktır, çünkü her bir birleşmede çeşitli dallardaki aramalar arasında çakışma yoktur: bilgi işlem zaman (ve yığın derinliği) toplam segment sayısı ile doğru orantılı olacaktır.