Bölüm 8: Dinamik Programlama
Çoktan Seçmeli · Temel Kavramlar
Soru 1: DP'nin İki Özelliği
Bir problemin dinamik programlamayla verimli çözülebilmesi için hangi iki özelliği taşıması gerekir?
B: Alt problemler tekrar tekrar çağrılmalıdır (tablo işe yarar) ve optimal çözüm alt problemlerin optimal çözümlerinden kurulabilmelidir (Bellman'ın optimallik ilkesi). Açgözlü seçim özelliği açgözlü algoritmaların koşuludur; DP tüm seçenekleri dener.
Çoktan Seçmeli · Temel Kavramlar
Soru 2: Neden Tablo Gerekmez?
Birleştirme sıralaması özyinelemeli olduğu hâlde neden bir DP tablosundan yararlanmaz?
A: Diziyi ikiye bölünce iki yarı ayrık parçalardır; hiçbir alt problem tekrar çözülmez, yani saklanacak tekrar yoktur. Bu böl ve fethettir. Fibonacci'de ise fib(3) gibi alt problemler defalarca çağrılır.
Çıktı Sorusu · Fibonacci
Soru 3: Çağrı Sayısı
Düz özyinelemeli fib metoduna bir çağrı sayacı eklendi. Kod ne yazdırır? Aynı hesap derstekiler gibi bellekleme ile yapılsaydı kaç çağrı olurdu?
static int cagri = 0; static long fib(int n) { cagri++; if (n <= 1) return n; return fib(n - 1) + fib(n - 2); } // main: System.out.println(fib(7) + " " + cagri);
Cevabı göster
13 41
- F(7) = 13. Çağrı sayısı 2 · F(n + 1) − 1 = 2 · 21 − 1 = 41: T(n) = T(n − 1) + T(n − 2) + 1.
- Bellekleme ile her fib(k) en çok bir kez açılır; fib(k) iki kez çağrılır (bir kez hesap, bir kez tablodan) → 2n − 1 = 13 çağrı.
Üstelden doğrusala: Θ(φⁿ) → O(n).
Adım Adım Çalıştırma · Fibonacci
Soru 4: Bellekleme: fib(4)
Bellekleme kullanan fib(4) çağrısında bellek dizisi nasıl dolar; hangi çağrı tablodan yanıtlanır?
bellek dizisi 0 ile başlar (0 = "henüz hesaplanmadı"). fib(4) tabloda yok → fib(3) çağrılır.
fib(3) tabloda yok → fib(2) çağrılır.
fib(2) tabloda yok → fib(1) çağrılır.
fib(1): taban durum, 1 döner.
fib(2)'de a = 1; şimdi fib(0) çağrılır: taban durum, 0 döner.
bellek[2] = 1 + 0 = 1 yazılır ve döndürülür.
fib(3)'te a = 1; fib(1) çağrılır → 1 (taban).
bellek[3] = 1 + 1 = 2.
fib(4)'te a = 2; fib(2) çağrılır: bellek[2] = 1 hazır, hiç alt çağrı yapılmadan döner.
bellek[4] = 2 + 1 = 3. Toplam 7 çağrı (2n − 1); düz özyineleme 9 çağrı yapardı.
static long[] bellek = new long[50]; static long fib(int n) { if (n <= 1) return n; // taban if (bellek[n] != 0) return bellek[n]; long a = fib(n - 1); long b = fib(n - 2); bellek[n] = a + b; return bellek[n]; }
Çoktan Seçmeli · Fibonacci
Soru 5: Bellekleme ve Tablolama
Bellekleme (yukarıdan aşağı) ve tablolama (aşağıdan yukarı) için aşağıdakilerden hangisi yanlıştır?
C yanlıştır: ikisi de her alt problemi bir kez çözer ve asimptotik süreleri aynıdır; tablolama özyineleme çağrısı yapmadığı için pratikte çoğu zaman daha hızlıdır. A, B ve D derste anlatılan özelliklerdir.
Çıktı Sorusu · 0/1 Sırt Çantası
Soru 6: En Büyük Değer
Eşyalar (v, w): (10, 5), (40, 4), (30, 6), (50, 3); kapasite W = 10. 0/1 sırt çantası tablosunun son satırını, en büyük değeri ve seçilen eşyaları bulun.
Cevabı göster
| i | K[i][0..10] |
|---|---|
| 1 | 0 0 0 0 0 10 10 10 10 10 10 |
| 2 | 0 0 0 0 40 40 40 40 40 50 50 |
| 3 | 0 0 0 0 40 40 40 40 40 50 70 |
| 4 | 0 0 0 50 50 50 50 90 90 90 90 |
K[4][10] = 90. Geri okuma: K[4][10] = 90 ≠ K[3][10] = 70 → eşya 4 (c = 7); K[3][7] = K[2][7] = 40 → eşya 3 yok; K[2][7] = 40 ≠ K[1][7] = 10 → eşya 2 (c = 3); K[1][3] = 0 → eşya 1 yok.
Seçim: eşya 2 + eşya 4 (40 + 50, ağırlık 7). Kalan 3 kg'a başka eşya sığmaz.
Çoktan Seçmeli · 0/1 Sırt Çantası
Soru 7: Açgözlü Neden Yanılır?
W = 10; eşyalar (değer, ağırlık): (30 ₺, 6 kg), (20 ₺, 5 kg), (20 ₺, 5 kg). Değer/ağırlık oranına göre açgözlü seçim ve optimal 0/1 çözüm kaç ₺ verir?
A: Oranlar 5, 4, 4: açgözlü önce 6 kg'lık eşyayı alır; kalan 4 kg'a 5 kg'lık eşyalar sığmaz → 30 ₺. İki 5 kg'lık eşya birlikte 10 kg, 40 ₺ eder. 50 ₺ ağırlık sınırını aşar (11 kg). Açgözlü yalnızca kesirli sırt çantasında optimaldir.
Çıktı Sorusu · 0/1 Sırt Çantası
Soru 8: Döngü Yönü
Tek eşya (değer 10, ağırlık 3) ve kapasite 9 için tek boyutlu tablo iki farklı yönde dolduruluyor. Kod ne yazdırır? Hangisi 0/1 sırt çantasıdır?
int v = 10, w = 3, W = 9; int[] dp = new int[W + 1]; int[] dq = new int[W + 1]; for (int c = W; c >= w; c--) // büyükten küçüğe dp[c] = Math.max(dp[c], v + dp[c - w]); for (int c = w; c <= W; c++) // küçükten büyüğe dq[c] = Math.max(dq[c], v + dq[c - w]); System.out.println(dp[W] + " " + dq[W]);
Cevabı göster
10 30
- Büyükten küçüğe: dp[c − 3] bu turda henüz güncellenmemiştir (eski satır) → eşya en çok bir kez alınır: 10 (0/1).
- Küçükten büyüğe: dq[3] = 10, dq[6] = 10 + dq[3] = 20, dq[9] = 30 → aynı eşya üç kez alınır: 30 (sınırsız sırt çantası).
Çoktan Seçmeli · 0/1 Sırt Çantası
Soru 9: Sözde-Polinom
0/1 sırt çantası DP'si O(n · W) sürer. Bu süre neden "sözde-polinom" (pseudo-polynomial) olarak adlandırılır?
D: W = 10⁹ yalnızca 30 bitle yazılır ama tablo 10⁹ sütun ister. Süre W'nin büyüklüğüne bağlıdır, uzunluğuna değil; bu yüzden problem NP-zor kalır ve DP yalnızca W küçükken pratiktir.
Çoktan Seçmeli · Sınırsız Sırt Çantası
Soru 10: Kaç Farklı Yol?
Paralar {2, 3, 5} ile 10 tutarı kaç farklı şekilde ödenebilir? (Sıra önemsiz; dış döngü paralar üzerinde: d[x] += d[x − c].)
D: {5, 5}, {2, 3, 5}, {2, 2, 3, 3}, {2, 2, 2, 2, 2} → 4. Döngüler yer değiştirirse (dış döngü tutar üzerinde) 2 + 3 ile 3 + 2 ayrı sayılır ve sıralı diziler sayılmış olur.
Adım Adım Çalıştırma · Alt Küme Toplamı
Soru 11: altKume Tablosu
altKume({3, 4, 5, 2}, 7) tablosu satır satır nasıl dolar?
a = {3, 4, 5, 2}, hedef 7. Sütun 0 hep ✓ (boş küme); satır 0'da diğer toplamlar elde edilemez.
i = 1, x = 3: üst satır kopyalanır; dp[i−1][j−3] ✓ olan j'ler de ✓ olur. Yeni toplamlar (mavi): 3.
i = 2, x = 4: üst satır kopyalanır; dp[i−1][j−4] ✓ olan j'ler de ✓ olur. Yeni toplamlar (mavi): 4, 7.
i = 3, x = 5: üst satır kopyalanır; dp[i−1][j−5] ✓ olan j'ler de ✓ olur. Yeni toplamlar (mavi): 5.
i = 4, x = 2: üst satır kopyalanır; dp[i−1][j−2] ✓ olan j'ler de ✓ olur. Yeni toplamlar (mavi): 2, 6.
dp[4][7] = true. Geri okuma: dp[2][7] ✓ ama dp[1][7] · → 4 seçildi (j = 3); dp[1][3] ✓ → 3. Alt küme {3, 4}; {5, 2} de geçerlidir.
boolean altKume(int[] a, int hedef) { int n = a.length; boolean[][] dp = new boolean[n + 1][hedef + 1]; for (int i = 0; i <= n; i++) dp[i][0] = true; // boş küme for (int i = 1; i <= n; i++) { int x = a[i - 1]; for (int j = 1; j <= hedef; j++) dp[i][j] = dp[i - 1][j] // x alınmaz || (x <= j && dp[i - 1][j - x]); } return dp[n][hedef]; }
Çoktan Seçmeli · Alt Küme Toplamı
Soru 12: Eşit Bölme
{1, 5, 11, 5} dizisinin toplamı eşit iki parçaya bölünüp bölünemeyeceğini alt küme toplamıyla nasıl buluruz ve sonuç nedir?
C: Toplam S = 22; bir parça S/2 = 11 ederse diğeri de 11 eder. {11} ya da {1, 5, 5} → evet. S tek olsaydı cevap doğrudan hayır olurdu; hedef 22 tüm dizinin kendisini sorar ve bölme hakkında bilgi vermez.
Adım Adım Çalıştırma · En Uzun Artan Alt Dizi
Soru 13: lis İzleme
lis({3, 1, 4, 1, 5, 9, 2, 6}) hangi değeri döndürür?
dp[i]: a[i]'de biten en uzun artan alt dizinin uzunluğu. Mavi: a[j] < a[i] olan önceki adaylar.
i = 0 (a = 3): önünde daha küçük öğe yok → dp[0] = 1.
i = 1 (a = 1): önünde daha küçük öğe yok → dp[1] = 1.
i = 2 (a = 4): adaylar 3, 1; en büyük dp j = 0 (dp = 1) → dp[2] = 2.
i = 3 (a = 1): önünde daha küçük öğe yok → dp[3] = 1.
i = 4 (a = 5): adaylar 3, 1, 4, 1; en büyük dp j = 2 (dp = 2) → dp[4] = 3.
i = 5 (a = 9): adaylar 3, 1, 4, 1, 5; en büyük dp j = 4 (dp = 3) → dp[5] = 4.
i = 6 (a = 2): adaylar 1, 1; en büyük dp j = 1 (dp = 1) → dp[6] = 2.
i = 7 (a = 6): adaylar 3, 1, 4, 1, 5, 2; en büyük dp j = 4 (dp = 3) → dp[7] = 4.
Sonuç 4 = max dp (ör. 3, 4, 5, 9 ya da 1, 4, 5, 6). dp[n − 1] de 4 ama bu tesadüf; cevap her zaman en büyük dp'dir. O(n²).
static int lis(int[] a) { int n = a.length, enUzun = 0; int[] dp = new int[n]; for (int i = 0; i < n; i++) { dp[i] = 1; // tek başına for (int j = 0; j < i; j++) if (a[j] < a[i] && dp[j] + 1 > dp[i]) dp[i] = dp[j] + 1; // uzat enUzun = Math.max(enUzun, dp[i]); } return enUzun; }
Çoktan Seçmeli · En Uzun Artan Alt Dizi
Soru 14: Cevap Hangi Hücrede?
Bir öğrenci lis metodunda enUzun yerine dp[n - 1] döndürüyor. {5, 1, 6, 2, 7, 0} için hatalı ve doğru sonuçlar nedir?
B: dp = [1, 1, 2, 2, 3, 1]. Son öğe 0 hiçbir diziyi uzatamaz → dp[5] = 1. LIS herhangi bir yerde bitebilir; doğru cevap max dp = 3 (5, 6, 7 ya da 1, 2, 7). 4 uzunluklu artan alt dizi yoktur.
Çıktı Sorusu · Ortak Alt Dizgi
Soru 15: Alt Dizgi ve Alt Dizi
"programlama" ve "gramer" için en uzun ortak alt dizgi (bitişik) ve en uzun ortak alt dizi (LCS) uzunlukları nedir? Ortak alt dizgiyi yazın; tablolardaki cevap hücreleri nerededir?
Cevabı göster
- En uzun ortak alt dizgi: "gram", uzunluk 4 (programlama'da 3–6, gramer'de 0–3). Cevap tablonun en büyük değeridir.
- LCS uzunluğu da 4: "gram"dan daha uzun ortak alt dizi yoktur (gramer'in kalan "er"i programlama'da m'den sonra sırayla geçmez). Cevap son hücre L[n][m]'dir.
- Ortak alt dizgi ≤ LCS her zaman; burada eşittir. "abdca" · "cbda" örneğinde 2 ve 3'tür.
Çıktı Sorusu · En Uzun Ortak Alt Dizi
Soru 16: lcs Uzunlukları
Dersteki lcs metodu (uzunluk döndürür) ile kod ne yazdırır? Her biri için bir LCS yazın.
System.out.println(lcs("DINAMIK", "DIAMOND"));
System.out.println(lcs("ABCBDAB", "BDCABA"));
System.out.println(lcs("ABC", ""));Cevabı göster
4 4 0
- DINAMIK · DIAMOND: "DIAM" (D, I, A, M sırayla ikisinde de var).
- ABCBDAB · BDCABA: "BCBA" (ya da "BDAB", "BCAB"); LCS tek değildir, uzunluğu tektir.
- Boş dizgiyle LCS boştur: L[0][m] = 0.
Zaman ve bellek O(m · n); yalnızca uzunluk gerekiyorsa iki satırla O(min(m, n)) bellek yeter.
Adım Adım Çalıştırma · Diğer Problemler
Soru 17: Kadane İzleme
En büyük toplamlı alt dizi (Kadane, V(i) = max(a[i], V(i−1) + a[i])): kadane({2, -3, 4, -1, -2, 1, 5, -3}) ne döndürür?
V(i): a[i]'de biten en büyük toplamlı alt dizinin toplamı. V(0) = a[0] = 2; enIyi = 2.
i = 1: V = max(-3, 2 + -3) = -1 (uzat); enIyi = 2.
i = 2: V = max(4, -1 + 4) = 4 (yeniden başla); enIyi = 4.
i = 3: V = max(-1, 4 + -1) = 3 (uzat); enIyi = 4.
i = 4: V = max(-2, 3 + -2) = 1 (uzat); enIyi = 4.
i = 5: V = max(1, 1 + 1) = 2 (uzat); enIyi = 4.
i = 6: V = max(5, 2 + 5) = 7 (uzat); enIyi = 7.
i = 7: V = max(-3, 7 + -3) = 4 (uzat); enIyi = 7.
Sonuç 7: alt dizi [4, −1, −2, 1, 5] (indis 2–6). Her durum O(1) → O(n) zaman, O(1) bellek.
static int kadane(int[] a) { int enIyi = a[0], v = a[0]; // V(0) for (int i = 1; i < a.length; i++) { v = Math.max(a[i], v + a[i]); // V(i) enIyi = Math.max(enIyi, v); } return enIyi; }
Çoktan Seçmeli · Diğer Problemler
Soru 18: Matris Zinciri
Matris zinciri çarpımında M[i][j] = min { M[i][k] + M[k+1][j] + pi−1 · pk · pj : i ≤ k < j }. n matris için zaman karmaşıklığı nedir?
B: O(n²) durum (i ≤ j çiftleri), her durumda k için O(n) seçenek denenir → O(n³). Tüm parantezlemeleri denemek Catalan sayısı kadar, yani üstel sürerdi. Kural yine "durum sayısı × durum başına iş"tir.
Klasik Soru · Diğer Problemler
Soru 19: DP Tasarımı: Para Üstü
Paralar c1, …, ck ve tutar X için "en az kaç para" problemini derste anlatılan adımlarla tasarlayın: durum, bağıntı, taban durum, doldurma sırası, tablo boyutu ve karmaşıklık. Paralar {1, 3, 4} ve X = 6 için tabloyu doldurun.
Cevabı göster
- Durum: P[x] = x tutarını ödemek için en az para sayısı.
- Bağıntı: P[x] = 1 + min P[x − c] (c ≤ x); taban: P[0] = 0.
- Sıra: x = 1, 2, …, X (küçük tutarlar önce hazır olmalı). Tablo: X + 1 hücre.
- Karmaşıklık: O(k · X) zaman, O(X) bellek (sözde-polinom).
P[6] = 1 + min(P[5], P[3], P[2]) = 1 + min(2, 1, 2) = 2 (3 + 3). Açgözlü 4 + 1 + 1 = 3 para verir. Hangi paraların seçildiği, her x için kullanılan c saklanarak geri okunur.