rev4: Sammaron kullanıcısı tarafından yapılan çok anlamlı bir yorum, belki de bu cevabın daha önce yukarıdan aşağıya ve aşağıdan yukarıya karıştırdığını belirtti. Başlangıçta bu cevap (rev3) ve diğer cevaplar "aşağıdan yukarıya memoization" ("alt problemleri varsayalım") dediğinde, ters olabilir (yani, "yukarıdan aşağıya" "alt problemleri varsayalım" ve " aşağıdan yukarıya "," alt problemleri oluştur "olabilir). Daha önce, hatırlamanın dinamik programlama alt türünün aksine farklı türde bir dinamik programlama olduğunu okumuştum. Abone olmamakla birlikte bu bakış açısını aktarıyordum. Literatürde uygun referanslar bulunana kadar bu cevabı terminolojiden bağımsız olarak yeniden yazdım. Bu yanıtı bir topluluk wikisine de dönüştürdüm. Lütfen akademik kaynakları tercih edin. Referans listesi:} {Edebiyat: 5 }
tekrarlamak
Dinamik programlama, hesaplamalarınızı yinelenen çalışmaların yeniden hesaplanmasını önleyecek şekilde sipariş etmekle ilgilidir. Ana bir probleminiz var (alt problemler ağacınızın kökü) ve alt problemler (alt ağaçlar). Alt problemler genellikle tekrarlanır ve çakışır .
Örneğin, favori Fibonnaci örneğini düşünün. Eğer saf bir özyinelemeli çağrı yaparsak, bu alt problemlerin tam ağacıdır:
TOP of the tree
fib(4)
fib(3)...................... + fib(2)
fib(2)......... + fib(1) fib(1)........... + fib(0)
fib(1) + fib(0) fib(1) fib(1) fib(0)
fib(1) fib(0)
BOTTOM of the tree
(Bazı diğer nadir problemlerde, bu ağaç bazı dallarda sonsuz olabilir, bu da sonlandırılmayı temsil eder ve bu nedenle ağacın tabanı sonsuz büyük olabilir. Ayrıca, bazı problemlerde tam ağacın neye benzediğini bilmiyor olabilirsiniz. Bu nedenle, hangi alt sorunların ortaya çıkacağına karar vermek için bir strateji / algoritmaya ihtiyacınız olabilir.)
Hatırlama, Tablolama
Karşılıklı olarak dışlanmayan en az iki ana dinamik programlama tekniği vardır:
Memoization - Bu laissez-faire bir yaklaşımdır: Tüm alt problemleri zaten hesapladığınızı ve en uygun değerlendirme sırasının ne olduğu hakkında hiçbir fikriniz olmadığını varsayarsınız. Genellikle, kökten özyinelemeli bir çağrı (veya yinelemeli bir eşdeğer) gerçekleştirirsiniz ve ya en uygun değerlendirme sırasına yaklaşacağınızı ya da en uygun değerlendirme sırasına ulaşmanıza yardımcı olacağınıza dair bir kanıt elde edeceğinizi umarsınız. Sonuçları önbelleğe aldığınız için özyinelemeli çağrının hiçbir zaman bir alt sorunu yeniden hesaplamamasını sağlar ve böylece yinelenen alt ağaçlar yeniden hesaplanmaz.
- Örnek: Fibonacci dizisini hesaplıyorsanız,
fib(100)
bunu sadece çağırırsınız ve bu fib(100)=fib(99)+fib(98)
, çağıracak fib(99)=fib(98)+fib(97)
, ... vs ... diyecektir fib(2)=fib(1)+fib(0)=1+0=1
. Sonra nihayet çözülecekti fib(3)=fib(2)+fib(1)
, ama yeniden hesaplamaya gerek yok fib(2)
, çünkü önbelleğe aldık.
- Bu ağacın tepesinden başlar ve yapraklardan / alt ağaçlardan gelen alt problemleri köke doğru değerlendirir.
Tablolama - Dinamik programlamayı "tablo doldurma" algoritması olarak da düşünebilirsiniz (genellikle çok boyutlu olsa da, bu 'tablo' çok nadir durumlarda Öklid olmayan geometriye sahip olabilir *). Bu, notlama gibidir ancak daha aktiftir ve bir adım daha içerir: Hesaplamalarınızı yapacağınız zamanı önceden seçmelisiniz. Bu, siparişin statik olması gerektiği anlamına gelmemeli, ancak nottan çok daha fazla esnekliğe sahip olduğunuz anlamına gelmelidir.
- örnek: Eğer fibonacci yapıyorsanız, bu sırayla sayıları hesaplamak için tercih edebilirsiniz:
fib(2)
, fib(3)
, fib(4)
... daha kolay gelecek olanlar hesaplayabilir böylece her değeri önbelleğe. Ayrıca bir tabloyu doldurmanın (başka bir önbellekleme biçimi) olduğunu düşünebilirsiniz.
- Şahsen 'tablolama' kelimesini çok fazla duymuyorum, ama çok iyi bir terim. Bazı insanlar bu "dinamik programlamayı" düşünüyor.
- Algoritmayı çalıştırmadan önce, programcı tüm ağacı dikkate alır, daha sonra alt problemleri belirli bir sırada köke doğru değerlendirmek için bir algoritma yazar, genellikle bir tablo doldurur.
- * dipnot: Bazen 'tablo' ızgara benzeri bağlantıya sahip dikdörtgen bir tablo değildir. Daha ziyade, bir ağaç gibi daha karmaşık bir yapıya veya sorunlu bölgeye özgü bir yapıya (örneğin, bir harita üzerinde uçuş mesafesi içindeki şehirler) veya hatta ızgara benzeri olsa da olmayan bir kafes diyagramına sahip olabilir. Örneğin, kullanıcı3290797 , bir ağaçtaki boşlukları doldurmaya karşılık gelen maksimum bağımsız kümeyi bulmak için dinamik bir programlama örneği bağladı .
Bir "dinamik programlama" paradigması içinde, en genel bulunuyor At (Ben, programcı bütün ağaç gördüğü söyleyebilirim sonraistediğiniz herhangi bir özelliği (genellikle zaman karmaşıklığı ve alan karmaşıklığı kombinasyonu) optimize edebilecek alt problemleri değerlendirmek için bir strateji uygulayan bir algoritma yazar. Stratejiniz belirli bir alt problemle bir yerden başlamalı ve belki de bu değerlendirmelerin sonuçlarına göre kendini uyarlayabilir. Genel olarak "dinamik programlama" anlamında, bu alt problemleri önbelleğe almayı deneyebilir ve daha genel olarak, belki de çeşitli veri yapılarındaki grafiklerde belirgin bir ayrım olan alt problemleri tekrar gözden geçirmekten kaçınabilirsiniz. Çoğu zaman, bu veri yapıları diziler veya tablolar gibi özünde bulunur. Artık ihtiyaç duymazsak alt problemlere çözümler atılabilir.)
[Daha önce, bu cevap yukarıdan aşağıya ve aşağıdan yukarıya terminoloji hakkında bir açıklama yapmıştı; Memoization ve Tabulation adlı bu terimlerle (tamamen olmasa da) birlikte olabilecek iki ana yaklaşım vardır. Çoğu kişinin kullandığı genel terim hala "Dinamik Programlama" dır ve bazı kişiler "Dinamik Programlama" nın bu alt türüne atıfta bulunmak için "Memoization" der. Bu cevap, topluluk akademik makalelerde uygun referansları bulana kadar hangisinin yukarıdan aşağıya ve aşağıdan yukarıya olduğunu söylemeyi reddeder. Sonuçta, terminolojiden ziyade ayrımı anlamak önemlidir.]
Lehte ve aleyhte olanlar
Kodlama kolaylığı
Memoization kodlamak çok kolaydır (genellikle * sizin için otomatik olarak yapan bir "memoizer" ek açıklama veya sarmalayıcı işlevi yazabilirsiniz) ve ilk yaklaşımınız olmalıdır. Tablolamanın dezavantajı, bir sipariş bulmanız gerektiğidir.
* (bu aslında sadece işlevi kendiniz yazıyorsanız ve / veya saf olmayan / işlevsel olmayan bir programlama dilinde kodluyorsanız kolaydır ... örneğin, bir kişi önceden derlenmiş bir fib
işlev yazdıysa , mutlaka kendisine özyinelemeli çağrılar yapar ve bu özyinelemeli çağrıların yeni memoized işlevinizi çağırmasını (ve orijinal unmemoized işlevini değil) aramasını sağlamadan işlevi sihirli bir şekilde hatırlayamazsınız.
tekrarlamasinda
Hem yukarıdan aşağıya hem de aşağıdan yukarıya, yineleme veya yinelemeli tablo doldurma ile uygulanabileceğini, ancak doğal olmayabilir.
Pratik kaygılar
Not ile, ağaç çok derinse (örn. fib(10^6)
), Yığın alanınız bitecek, çünkü her gecikmeli hesaplama yığına konulmalı ve 10 ^ 6 tanesine sahip olacaksınız.
Optimalliği
Alt problemleri ziyaret ettiğiniz (veya almaya çalıştığınız) sipariş, özellikle bir alt problemi hesaplamak için birden fazla yol varsa (normalde önbellekleme bunu çözebilir, ancak teorik olarak önbelleklemenin bazı egzotik durumlarda değil). Memoization genellikle zaman karmaşıklığınızı alan karmaşıklığınıza ekler (örneğin, tablo ile hesaplamaları atmak için daha fazla özgürlüğünüz vardır, örneğin Fib ile tablo kullanmak O (1) alanını kullanmanıza izin verir, ancak Fib ile not kullanmak O (N) kullanır yığın alanı).
Gelişmiş optimizasyonlar
Ayrıca son derece karmaşık bir sorun yaşıyorsanız, tablolama yapmaktan başka seçeneğiniz olmayabilir (veya en azından notu gitmesini istediğiniz yere yönlendirmede daha aktif bir rol üstlenebilirsiniz). Ayrıca, optimizasyonun kesinlikle kritik olduğu bir durumdaysanız ve optimizasyon yapmanız gerekiyorsa, tablolama, hatırlamanın aksi takdirde aklı başında bir şekilde yapmanıza izin vermeyeceği optimizasyonları yapmanıza izin verecektir. Benim düşünceme göre, normal yazılım mühendisliğinde, bu iki durumdan hiçbiri ortaya çıkmadı, bu yüzden bir şey (yığın alanı gibi) tablolamayı gerekli kılmadığı sürece sadece memoization ("cevaplarını önbelleğe alan bir işlev") kullanırım ... teknik olarak bir yığın patlamasını önlemek için 1) izin veren dillerde yığın boyutu sınırını artırabilir veya 2) yığınınızı sanallaştırmak için sabit bir ekstra iş faktörü yiyebilirsiniz (ick),
Daha karmaşık örnekler
Burada, sadece genel DP problemleri değil, aynı zamanda hatırlatma ve tablolamayı ilginç bir şekilde ayırt eden özel ilgi gösteren örnekleri listeliyoruz. Örneğin, bir formülasyon diğerinden daha kolay olabilir veya temel olarak tablolama gerektiren bir optimizasyon olabilir:
- iki boyutlu tablo doldurma algoritmasının önemsiz bir örneği olarak ilginç olan düzenleme mesafesini hesaplamak için algoritma [ 4 ]