Özyinelemeli algoritmamın zaman karmaşıklığını azaltmak için ne zaman dinamik programlamayı kullanabilirim?


13

Dinamik programlama, yinelemeli algoritma gerçekleştirmek için gereken süreyi azaltabilir. Dinamik programlamanın algoritmaların zaman karmaşıklığını azaltmaya yardımcı olabileceğini biliyorum. Genel koşullar, özyinelemeli bir algoritmadan memnun kaldığında, dinamik programlama kullanmanın algoritmanın zaman karmaşıklığını azaltacağı anlamına mı geliyor? Dinamik programlamayı ne zaman kullanmalıyım?


Yanıtlar:


9

Dinamik programlama, yinelemeli algoritmanızın aynı durumlara (giriş parametreleri) birçok kez ulaştığını bulması yararlıdır. Özyinelemeli algoritmalardan, bellek olarak bilinen dinamik programlamaya genel bir dönüşüm vardır, burada özyinelemeli yordamınız tarafından şimdiye kadar hesaplanan tüm sonuçları depolayan bir tablo vardır. Daha önce kullanılmış olan bir girdi kümesinde özyinelemeli yordam çağrıldığında, sonuçlar tablodan alınır. Bu yinelemeli Fibonacci'yi yinelemeli Fibonacci'ye azaltır.

Dinamik programlama daha akıllı olabilir ve daha spesifik optimizasyonlar uygulayabilir. Örneğin, bazen herhangi bir zamanda tablonun tamamını belleğe kaydetmeye gerek yoktur.


Sayaç, notun alan karmaşıklığı giriş verilerinden daha büyük olduğunda (belki de sadece> O (N)), dinamik programlamanın yardımcı olmayacağı ihtimalidir. Yani, nadiren aynı durumla karşılaştığınızda.
edA-qa mort-ora-y

1
Memoisation! = Dinamik programlama!
Raphael

1
Bunu söylediğimizi sanmıyorum, ama soru zaman karmaşıklığını azalttığını gösteriyor. Dinamik programlama kendi başına sorunu basitçe bölümlere ayırır. Dinamik programlama + notlama, mümkün olduğunda zaman karmaşıklığını iyileştirmenin genel bir yoludur .
edA-qa mort-ora-y

@ edA-qamort-ora-y: Doğru. OP'nin kavramları karıştırdığı / karıştırdığı için bunu açıkça belirtmek önemlidir.
Raphael

8

Özyinelemeli algoritmanızı hızlandırmaya çalışıyorsanız, bellek yeterli olabilir. Bu işlev çağrılarının sonuçlarını saklama tekniği, böylece aynı parametrelere sahip gelecek çağrılar sadece sonucu yeniden kullanabilir. Bu, eğer fonksiyonunuz (ve sadece eğer)

  • yan etkisi yoktur ve
  • yalnızca parametrelerine bağlıdır (yani bazı durumlara bağlı değildir).

Fonksiyon aynı parametrelerle tekrar tekrar çağrıldığında (ve sadece) zamandan tasarruf etmenizi sağlar. Popüler örnekler arasında Fibonacci sayılarının özyinelemeli tanımı, yani

f(0)=0f(1)=1f(n+2)=f(n+1)+f(n), n0

ff(n)f(n+1)

Bunun aksine, birleştirme sıralaması gibi algoritmalar için notlamanın işe yaramaz olduğunu unutmayın: genellikle az sayıda (varsa) kısmi liste aynıdır ve eşitlik kontrolleri pahalıdır (sıralama sadece biraz daha maliyetlidir!).

Pratik uygulamalarda, sonuçları nasıl sakladığınız performans açısından büyük önem taşır. Karma tabloları kullanmak bariz bir seçim olabilir, ancak yerelliği bozabilir. Parametreleriniz negatif olmayan tamsayılarsa, diziler doğal bir seçimdir, ancak yalnızca bazı girişler kullanırsanız büyük bellek yüküne neden olabilir. Dolayısıyla, memoizasyon, etki ve maliyet arasında bir değiş tokuştur; İşe yarayıp yaramayacağı sizin özel senaryonuza bağlıdır.


Dinamik programlama tamamen başka bir yaratıktır. Bu özellik ile ilgili sorunlar için geçerlidir

  • alt problemlere ayrılabilir (muhtemelen birden fazla şekilde),
  • bu alt problemler bağımsız olarak çözülebilir,
  • Bu alt problemlerin (optimal) çözümleri, orijinal sorunun (optimal) çözümleriyle birleştirilebilir ve
  • alt problemler aynı özelliğe sahiptir (veya önemsizdir).

Bu genellikle (dolaylı olarak) insanlar Bellman'ın Optimallik İlkesini çağırdığında ima edilir .

Şimdi, bu sadece belirli bir özyineleme ile ifade edilebilecek bir sınıf problemini tanımlamaktadır . Bunların değerlendirilmesi (genellikle) etkilidir çünkü memoizasyon büyük etkiye uygulanabilir (yukarıya bakınız); genellikle, daha büyük sorunların bir parçası olarak daha küçük alt problemler ortaya çıkar. Popüler örnekler düzenleme mesafesini ve Bellman-Ford algoritmasını içerir .


Dinamik programlamanın daha iyi zaman karmaşıklığına yol açacağını, ancak hatırlamanın işe yaramayacağını (veya en azından o kadar da olmayacağını) söylüyorsunuz? Hiç örneğin var mı? Yoksa dinamik programlamanın yalnızca hatırlamanın olduğu sorunların bir alt kümesi için yararlı olduğunu mu söylüyorsunuz?
svick

@svick: Dinamik programlama kendi başına hiçbir şeyi hızlandırmaz , yalnızca DP özyineleme notu ile değerlendirilirse (genellikle (!) durum). Yine: DP problemleri özyineleme açısından modellemenin bir yoludur , memoizasyon uygun özyinelemeli algoritmaları hızlandırmak için bir tekniktir (DP olsun ya da olmasın). Her ikisini de doğrudan karşılaştırmak mantıklı değil. Tabii ki bir problemi DP olarak modellemeye çalışıyorsunuz çünkü memoisation uygulamasını bekliyorsunuz ve bu yüzden naif (r) yaklaşımlardan daha hızlı çözüyorsunuz. Ancak DP bakış açısı da her zaman en verimli algoritmaya yol açmaz.
Raphael

Birden fazla işlemciniz varsa dinamik programlama, parçaları paralel hale getirebileceğiniz için gerçek dünya performansını büyük ölçüde artırır. Aslında zaman karmaşıklığını değiştirmez.
edA-qa mort-ora-y

@ edA-qamort-ora-y: Bu herhangi bir özyineleme için geçerlidir . Ancak, bellek hızının işlemci sınırlarına göre daha az verimli olması nedeniyle bunun iyi bir hızlanma sağladığı açık değildir.
Raphael

Düzeltme: DP nükslerinin saf olarak değerlendirilmesi hala kaba kuvvetten (çok) daha hızlı olabilir; bakınız burada .
Raphael
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.