Geriye dönük izleme ile derinlemesine ilk arama arasındaki fark nedir?
Geriye dönük izleme ile derinlemesine ilk arama arasındaki fark nedir?
Yanıtlar:
Geri izleme daha genel amaçlı bir algoritmadır.
Önce Derinlik arama , ağaç yapılarını aramayla ilgili özel bir geri izleme biçimidir. Wikipedia'dan:
Bir tanesi kökten başlar (grafik durumunda kök olarak bir düğüm seçer) ve geriye doğru izlemeye başlamadan önce her dal boyunca mümkün olduğunca uzağa araştırma yapar.
Bir ağaçla çalışmanın bir parçası olarak geri izleme kullanır, ancak bir ağaç yapısıyla sınırlıdır.
Geriye dönük izleme, mantıksal bir ağaç olsun ya da olmasın, etki alanının bölümlerinin elimine edilebildiği her tür yapıda kullanılabilir. Wiki örneği bir satranç tahtası ve belirli bir problem kullanır - belirli bir harekete bakabilir ve onu ortadan kaldırabilir, ardından bir sonraki olası hamleye geri dönebilir, onu ortadan kaldırabilirsiniz, vb.
Bir başka ilgili sorunun cevabının daha fazla içgörü sunduğunu düşünüyorum .
Bana göre, geriye dönük izleme ile DFS arasındaki fark, geri izlemenin örtük bir ağacı ele alması ve DFS'nin açık bir ağaçla ilgilenmesidir. Bu önemsiz görünüyor ama çok şey ifade ediyor. Geriye dönük izleme ile bir problemin arama alanı ziyaret edildiğinde, örtük ağaç içinden geçilir ve ortasında budanır. Yine de DFS için, ilgilendiği ağaç / grafik açıkça oluşturulmuştur ve kabul edilemez durumlar, herhangi bir arama yapılmadan önce zaten atılmış, yani budanmış, ortadan kaldırılmıştır.
Bu nedenle, geri izleme örtük ağaç için DFS'dir, DFS ise budama olmadan geriye doğru izlenir.
Geriye dönük izleme genellikle DFS artı arama ayıklama olarak uygulanır. Önce yol boyunca kısmi çözümler inşa ederek arama alanı ağaç derinliğini aşarsınız. Brute-force DFS, pratik olarak anlamlı olmayanlar da dahil olmak üzere tüm arama sonuçlarını oluşturabilir. Bu aynı zamanda tüm çözümleri (n! Veya 2 ^ n) oluşturmak için çok verimsiz olabilir. Bu nedenle, gerçekte DFS'yi yaptığınız gibi, gerçek görev bağlamında anlam ifade etmeyen kısmi çözümleri de ayarlamanız ve geçerli optimum çözümlere yol açabilecek kısmi çözümlere odaklanmanız gerekir. Bu gerçek geri izleme tekniğidir - kısmi çözümleri olabildiğince erken atarsınız, geri adım atarsınız ve tekrar yerel optimum bulmaya çalışırsınız.
BFS kullanarak arama alanı ağacında gezinmek ve yol boyunca geri izleme stratejisi yürütmek için hiçbir şey durmuyor, ancak pratikte mantıklı değil çünkü arama durumunu katman katman kuyrukta saklamanız gerekecek ve ağaç genişliği katlanarak yüksekliğe büyüyor, böylece çok hızlı bir şekilde çok fazla alanı boşa harcardık. Bu nedenle ağaçlar genellikle DFS kullanılarak geçilir. Bu durumda arama durumu yığında saklanır (çağrı yığını veya açık yapı) ve ağaç yüksekliğini aşamaz.
IMHO, cevapların çoğu ya büyük ölçüde belirsizdir ve / veya doğrulanacak herhangi bir referans yoktur. Öyleyse çok net bir açıklamayı bir referansla paylaşmama izin verin .
İlk olarak, DFS genel bir grafik geçiş (ve arama) algoritmasıdır. Böylece herhangi bir grafiğe (hatta ormana) uygulanabilir. Ağaç özel bir Grafik türüdür, bu nedenle DFS, ağaç için de çalışır. Esasen, bunun sadece bir ağaç veya benzerleri için işe yaradığını söylemeyi bırakalım.
[1] 'e göre, Backtracking, esas olarak alan (bellek) tasarrufu için kullanılan özel bir DFS türüdür. Bahsetmek üzere olduğum ayrım kafa karıştırıcı görünebilir, çünkü bu türden Grafik algoritmalarında bitişik liste temsillerine çok alıştık ve bir düğümün tüm yakın komşularını ziyaret etmek için yinelemeli model ( ağaç için bu hemen çocuklarıdır ) , get_all_immediate_neighbors'ın kötü bir şekilde uygulanmasının , temel alınan algoritmanın bellek kullanımlarında bir farka neden olabileceğini genellikle göz ardı ederiz .
Ayrıca, bir grafik düğümünde dallanma faktörü b ve çap h varsa ( bir ağaç için bu ağaç yüksekliğidir ), bir düğümü ziyaret etmenin her adımında tüm yakın komşuları saklarsak, bellek gereksinimleri büyük-O (bh) olacaktır . Bununla birlikte, bir seferde yalnızca tek bir (hemen) komşu alır ve onu genişletirsek, bellek karmaşıklığı büyük-O (h) 'ye düşer . İlk uygulama türü DFS olarak adlandırılırken , ikinci tür Geriye İzleme olarak adlandırılır .
Şimdi görüyorsunuz, yüksek seviyeli dillerle çalışıyorsanız, büyük olasılıkla aslında DFS kisvesi altında Backtracking kullanıyorsunuz. Dahası, çok büyük bir problem seti için ziyaret edilen düğümleri takip etmek gerçekten bellek yoğun olabilir; get_all_immediate_neighbors (veya sonsuz döngüye girmeden bir düğümü yeniden ziyaret etmeyi başarabilen algoritmalar) için dikkatli bir tasarım çağrısı .
[1] Stuart Russell ve Peter Norvig, Yapay Zeka: Modern Bir Yaklaşım, 3. Baskı
Donald Knuth'a göre durum aynı. N-queens ve Sudoku çözücü gibi "ağaç dışı" problemleri çözmek için kullanılan Dancing Links algoritmasıyla ilgili makalesinde yer alan bağlantı burada.
Geriye dönük izleme, derinlemesine arama olarak da adlandırılır
DFS'nin özel bir geri izleme biçimi olduğunu söyleyebilirim; geri izleme, DFS'nin genel biçimidir.
DFS'yi genel sorunlara genişletirsek, buna geri izleme diyebiliriz. Ağaç / grafikle ilgili sorunlara geri dönüşü kullanırsak, buna DFS diyebiliriz.
Algoritmik açıdan aynı fikri taşırlar.
Önce derinlik, bir ağaçta gezinmek veya arama yapmak için bir algoritmadır. Buraya bakın . Geriye dönük izleme, bir çözüm adayının oluşturulduğu ve daha sonra eski bir duruma geri dönülerek atıldığı her yerde kullanılan çok daha geniş bir terimdir. Buraya bakın . Önce derinlik araması, önce bir şubeyi (çözüm adayı) aramak için geriye doğru izlemeyi kullanır ve başarılı olmazsa diğer şubeleri / dalları araştırır.
IMO, geri izlemenin herhangi bir belirli düğümünde, ilk olarak alt düğümlerinin her birine dallanmayı derinleştirmeye çalışırsınız, ancak alt düğümlerden herhangi birine dalmadan önce, önceki çocuğun durumunu "silmeniz" gerekir (bu adım geri ana düğüme yürüyün). Başka bir deyişle, her kardeşin durumu birbirini etkilememelidir.
Aksine, normal DFS algoritması sırasında, genellikle bu kısıtlamaya sahip olmazsınız, sonraki kardeş düğümü oluşturmak için önceki kardeş durumunu silmeniz (geri izleme) gerekmez.
DFS, bir grafiği keşfetmek veya grafikte gezinmek istediğiniz yolu açıklar. Seçim verildiğinde mümkün olduğunca derine inme kavramına odaklanır.
Geri izleme, genellikle DFS aracılığıyla uygulanırken, daha çok, ödün vermeyen arama alt alanlarını olabildiğince erken budama kavramına odaklanır.
Bir de derinlemesine arama , sen ağacın kökünde başlar ve daha sonra, her şube boyunca kadarıyla sizi keşfetmek sarfınazar sonraki her ebeveyn düğümüne ve 's çocukları çapraz
Geriye dönük izleme, bir hedefin sonundan başlamak ve aşamalı olarak geriye doğru giderek bir çözüm geliştirmek için kullanılan genel bir terimdir.
Fikir - Herhangi bir noktadan başlayın, istenen son nokta olup olmadığını kontrol edin, eğer öyleyse, o zaman bir çözüm bulduk, sonraki olası tüm konumlara gider ve daha ileri gidemezsek, önceki konuma geri dönün ve o akımı işaretleyen diğer alternatifleri arayın yol bizi çözüme götürmez.
Artık geri izleme ve DFS, 2 farklı soyut veri türünde uygulanan aynı fikre verilen 2 farklı addır.
Fikir matris veri yapısına uygulanırsa, biz buna geri izleme diyoruz.
Aynı fikir ağaç veya grafiğe uygulanıyorsa ona DFS diyoruz.
Buradaki klişe, bir matrisin grafiğe ve grafiğin matrise dönüştürülebilmesidir. Yani aslında fikri uyguluyoruz. Bir grafikte buna DFS, matriste ise geri izleme diyoruz.
Her iki algoritmadaki fikir aynı.
Geriye dönük izleme, belirli sonlandırma koşulları ile derinlemesine ilk araştırmadır.
Her adım için bir karar verdiğiniz, bu kararın çağrı yığınına bir çağrı olduğu (ilk derinlemesine araştırmanızı gerçekleştiren) bir labirentte yürümeyi düşünün ... sonuna ulaşırsanız, yolunuza geri dönebilirsiniz. Ancak, bir çıkmaza ulaşırsanız, belirli bir karardan geri dönmek istersiniz, özünde çağrı yığınınızdaki bir işlevden geri dönersiniz.
Geriye dönmeyi düşündüğümde umursuyorum
Ben geriye benim videoda açıklamak burada .
Geri izleme kodunun bir analizi aşağıdadır. Bu geri izleme kodunda, belirli bir toplam veya hedefle sonuçlanacak tüm kombinasyonları istiyorum. Bu nedenle, çağrı yığınımı çağıran 3 kararım var, her kararda hedef numaraya ulaşmak için yolumun bir parçası olarak bir numara seçebilir, bu sayıyı atlayabilir veya seçip tekrar seçebilirim. Ve sonra bir fesih koşuluna ulaşırsam, geri izleme adımım sadece geri dönmektir . Geri dönüş, geri izleme adımıdır çünkü çağrı yığınındaki çağrıdan çıkar.
class Solution:
"""
Approach: Backtracking
State
-candidates
-index
-target
Decisions
-pick one --> call func changing state: index + 1, target - candidates[index], path + [candidates[index]]
-pick one again --> call func changing state: index, target - candidates[index], path + [candidates[index]]
-skip one --> call func changing state: index + 1, target, path
Base Cases (Termination Conditions)
-if target == 0 and path not in ret
append path to ret
-if target < 0:
return # backtrack
"""
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
"""
@desc find all unique combos summing to target
@args
@arg1 candidates, list of ints
@arg2 target, an int
@ret ret, list of lists
"""
if not candidates or min(candidates) > target: return []
ret = []
self.dfs(candidates, 0, target, [], ret)
return ret
def dfs(self, nums, index, target, path, ret):
if target == 0 and path not in ret:
ret.append(path)
return #backtracking
elif target < 0 or index >= len(nums):
return #backtracking
# for i in range(index, len(nums)):
# self.dfs(nums, i, target-nums[i], path+[nums[i]], ret)
pick_one = self.dfs(nums, index + 1, target - nums[index], path + [nums[index]], ret)
pick_one_again = self.dfs(nums, index, target - nums[index], path + [nums[index]], ret)
skip_one = self.dfs(nums, index + 1, target, path, ret)