SEN2212 · 12. hafta · Analyzing and implementing greedy algorithms.

Açgözlü algoritmalar: etkinlik seçimi, kesirli sırt çantası, para üstü

Greedy fikri, ne zaman doğru sonuç verdiği ve ne zaman çöktüğü. Etkinlik seçimi, kesirli ve 0/1 sırt çantası, para üstü örnekleri ve karşı örnekleriyle.

greedy algorithmgreedy-choice propertyoptimal substructureactivity selectioninterval schedulingfractional knapsack0/1 knapsackvalue-to-weight ratiocoin changecounterexampledynamic programming

Greedy (açgözlü) algoritma her adımda o an en iyi görünen seçimi yapar ve bir daha o seçimi sorgulamaz. Geri dönüş yok, tüm olasılıkları deneme yok. Bu yüzden hızlıdır ve kodu kısadır. Sorun şu: her problemde doğru cevap vermez. Sınavda iki tip soru gelir. Biri “greedy’yi çalıştır, sonucu yaz” (etkinlik listesi, çanta değeri, madeni paralar). Diğeri “bu greedy kural yanlış, karşı örnek ver”.

Altın kurallar:

  1. Greedy = yerel en iyi seçim, geri dönüş yok.
  2. Doğru olması için iki özellik lazım: greedy-choice property ve optimal substructure.
  3. Yanlışlığını göstermek için tek karşı örnek yeter. Küçük, 2-3 elemanlı örnek kur.
  4. Etkinlik seçiminde ölçüt bitiş zamanıdır, başlangıç ya da süre değil.
  5. Bölünebilen şeyde (kesirli) greedy çalışır, bölünemeyen 0/1’de çalışmaz.

Greedy ne zaman doğrudur?

İki özellik birlikte varsa greedy optimum verir:

  • Greedy-choice property: En iyi görünen ilk seçimi içeren bir optimum çözüm her zaman vardır. Yani ilk adımda greedy seçim yapmak seni optimumdan uzaklaştırmaz.
  • Optimal substructure: İlk seçimden sonra geriye kalan problem aynı türden daha küçük bir problemdir ve onun optimum çözümü, ilk seçimle birleşince bütünün optimumunu verir.

Bunu kanıtlamanın standart yolu değiştirme argümanıdır (exchange argument): herhangi bir optimum çözüm al, ilk elemanını greedy seçimle değiştir, çözümün hâlâ geçerli ve aynı iyilikte olduğunu göster.

Dinamik programlama (DP) ile fark: DP her alt problemin tüm seçeneklerini dener ve tabloya yazar. Greedy sadece birini seçer. DP daha güvenli, greedy daha hızlı.

Etkinlik seçimi (activity selection)

Bir salon var, her etkinliğin başlangıç ve bitiş zamanı belli. Çakışmayan en çok sayıda etkinliği seç. Bir etkinlik, öncekinin bittiği anda başlayabilir.

Greedy kural: Etkinlikleri bitiş zamanına göre sırala. En erken biteni al. Sonra başlangıcı son seçilenin bitişinden önce olmayan ilk etkinliği al. Böyle devam et.

Örnek: a(1,3), b(2,5), c(4,6), d(6,8), e(5,9), f(7,10), g(9,11), h(10,12), i(11,13).

zaman  0123456789012345
a  1-3  ==
b  2-5   ===
c  4-6     ==
d  6-8       ==
e  5-9      ====
f  7-10       ===
g  9-11         ==
h 10-12          ==
i 11-13           ==
etkinlik  başlangıç  sonBitiş  karar
a(1,3)    1 >= -∞     -∞      AL, son=3
b(2,5)    2 <  3      3       atla
c(4,6)    4 >= 3      3       AL, son=6
d(6,8)    6 >= 6      6       AL, son=8
e(5,9)    5 <  8      8       atla
f(7,10)   7 <  8      8       atla
g(9,11)   9 >= 8      8       AL, son=11
h(10,12)  10 < 11     11      atla
i(11,13)  11 >= 11    11      AL, son=13
earliest finish: [a(1,3), c(4,6), d(6,8), g(9,11), i(11,13)]
optimum count (brute force): 5

Neden doğru? En erken biten etkinlik, salonu en erken boşaltır. Optimum bir çözümün ilk etkinliğini onunla değiştirirsen hiçbir çakışma doğmaz (o daha erken ya da aynı anda bitiyor). Kalan problem “son bitişten sonra başlayanlar” alt problemi.

Yanlış kurallar ve karşı örnekleri

KuralKarşı örnekKuralın sonucuOptimum
En erken başlayanp(0,10), q(1,4), r(5,8)p (1 tane)q, r (2)
En kısa sürelix(0,5), y(4,7), z(6,11)y (1 tane)x, z (2)
earliest start picks [p] vs finish [q(1,4), r(5,8)]
shortest picks [y] vs finish [x(0,5), z(6,11)]

TUZAK · “sınır” koşulu. Soruda “an activity may start when the previous one finishes” diyorsa karşılaştırma >=, demiyorsa >. d(6,8) bu yüzden c(4,6)‘dan sonra alınabildi.

Sırt çantası problemi (knapsack)

Kapasitesi W olan bir çanta ve her birinin ağırlığı (wiw_i) ve değeri (viv_i) olan eşyalar var. Toplam değeri en büyük yap.

Örnek eşyalar: A(6 kg, 30), B(10 kg, 40), C(4 kg, 28), D(8 kg, 24). Kapasite 15.

Eşyawvv/w
C4287
A6305
B10404
D8243

Kesirli (fractional): greedy optimum

Eşyayı bölebiliyorsan (un, altın tozu gibi) kilo başına değeri en yüksek olandan başla, sığdığı kadar al, son eşyayı böl.

  take 4/4 of C (ratio 7.0) total=28.0
  take 6/6 of A (ratio 5.0) total=58.0
  take 5/10 of B (ratio 4.0) total=78.0
fractional value 78.0

Neden doğru? Çantadaki her kilo, en pahalı kilo ile doldurulmalı. Daha düşük oranlı bir kiloyu daha yüksek oranlı bir kiloyla değiştirmek her zaman değeri artırır.

0/1: greedy çöker

Eşyayı bölemiyorsan aynı kural yanlış sonuç verir:

  greedy 0/1 picks C A value 58
  optimal 0/1 picks B C value 68

C ve A’yı aldıktan sonra 5 kg boş kaldı ama B ve D sığmıyor. Kapasitenin bir kısmı boşa gitti. B + C ise 14 kg ile 68 yapıyor. 0/1 sırt çantası DP ile O(nW)O(nW) sürede çözülür (bu derste DP’ye girmiyoruz; greedy’nin neden çöktüğünü bilmen yeter).

TUZAK · oranı int bölmeyle hesaplama. v[i] / w[i] iki int ise 7/2 gibi değerler kesilir ve sıralama bozulur. (double) v[i] / w[i] yaz.

Para üstü (coin change)

Bir tutarı en az sayıda madeni parayla öde. Greedy kural: her adımda tutara sığan en büyük madeni parayı ver.

Madeni paralar {25, 10, 5, 1}, tutar 68:

kalan  verilen
68     25
43     25
18     10
 8      5
 3      1
 2      1
 1      1
 0      → 7 madeni para

Bu tür “standart” sistemlerde (25-10-5-1, ya da 50-20-10-5-1) greedy optimumdur. Ama her sistemde değil:

{1,4,6} 8 greedy [6, 1, 1] dp 2
{1,7,10} 14 greedy [10, 1, 1, 1, 1] dp 2

8 için 4 + 4 iki madeni para; greedy 6’yı kaptığı için kalan 2’yi 1’lerle ödemek zorunda kaldı. 14 için 7 + 7 yerine 10 + 1 + 1 + 1 + 1 verdi. Genel çözüm DP:

dp[0]=0,dp[a]=min⁡c≤a(dp[a−c]+1)dp[0] = 0,\qquad dp[a] = \min_{c \le a} \big(dp[a-c] + 1\big)

Sınavda greedy sorusu nasıl çözülür?

Üç tip soru için üç kalıp:

"Run the greedy":
  ölçütü yaz (bitiş, oran, büyük para)
  sırala, tabloyla tek tek karar ver
"Is greedy optimal?":
  2-3 elemanlı karşı örnek ara
  bulamazsan değiştirme argümanı kur
"Write the method":
  indeksleri ölçüte göre sırala
  tek döngü, koşul tutuyorsa al

Karşı örnek ararken şu soruyu sor: “Greedy’nin ilk seçimi, daha iyi iki seçimi birden engelleyebilir mi?” Etkinlik seçiminde uzun ve erken başlayan bir etkinlik, para üstünde tutarı garip bir kalana bırakan büyük bir madeni para, 0/1 çantada boşluk bırakan küçük ama oranı yüksek bir eşya bu rolü oynar. Kesirli çantada ve “en erken biten” kuralında böyle bir engel kurulamaz; bu yüzden onlar doğrudur.

Greedy algoritmalar bu derste nerede?

AlgoritmaGreedy seçimHafta
Dijkstraen küçük geçici mesafeli düğümü kesinleştir11
Huffmanen küçük iki frekansı birleştir12
Primağaca en ucuz bağlanan düğümü ekle13
Kruskaldöngü kurmayan en ucuz kenarı ekle13
Etkinlik seçimien erken biteni al12

Hepsinin doğruluğu, yukarıdaki iki özelliğin o problem için kanıtlanmasına dayanır. Dijkstra’nın negatif kenarda çökmesi de greedy-choice property’nin bozulmasıdır.

Sık yapılan hatalar

Yanlış düşünceDoğrusu
Greedy her optimizasyon probleminde doğruSadece iki özellik varsa; yoksa karşı örnek bulunur
Etkinlik seçiminde en erken başlayanı alEn erken BİTENİ al
Etkinlik seçiminde en kısa olanı alKarşı örnek: x(0,5), y(4,7), z(6,11)
0/1 sırt çantasında oran greedy’si optimumSadece kesirli versiyonda; 0/1 için DP
Kesirli çantada en değerli eşyadan başlaDeğer değil, değer/ağırlık oranı
Greedy para üstü her para sisteminde optimum{1,4,6} ve 8: greedy 3, optimum 2
s ve f dizilerini ayrı ayrı sıralaÇiftler bozulur; indeksleri bitişe göre sırala

Kendini test et

Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.

Soru 1orta

Activities (start, finish): a(1,3), b(2,5), c(4,6), d(6,8), e(5,9), f(7,10), g(9,11), h(10,12), i(11,13). An activity may start exactly when the previous one finishes. Using the earliest-finish-time greedy rule, which activities are selected?

Cevabı göster
a, c, d, g, i (5 activities)

Bitişe göre sırala (zaten sıralı). Son bitiş = -∞.
a(1,3) al, son=3. b başlangıç 2 < 3 atla. c(4,6) al, son=6. d(6,8): 6 ≥ 6 al, son=8. e 5 < 8, f 7 < 8 atla. g(9,11) al, son=11. h 10 < 11 atla. i(11,13) al.
Kaba kuvvet de en fazla 5 etkinlik buluyor; greedy optimum.

Soru 2kolay

Which greedy rule always gives a maximum-size set of compatible activities?

  1. Earliest start time first
  2. Shortest duration first
  3. Earliest finish time first
  4. Fewest conflicts first
Cevabı göster
C

En erken biten etkinlik, kalan zamanı en çok boşaltan seçimdir. Değiştirme argümanı (exchange argument): herhangi bir optimum çözümün ilk etkinliğini en erken bitenle değiştirsen çakışma çıkmaz. Diğer kuralların hepsine karşı örnek vardır.

Soru 3orta

Give the result of the earliest-start-time rule on p(0,10), q(1,4), r(5,8). What is the optimum?

Cevabı göster
Earliest start picks only p (1 activity); optimum is q, r (2)

p en erken başlıyor (0) ama 10'a kadar sürüyor ve q ile r'nin ikisiyle de çakışıyor. Bitişe göre greedy q(1,4) sonra r(5,8) alır: 2 etkinlik. Tek karşı örnek, bir kuralın yanlış olduğunu kanıtlamaya yeter.

Soru 4orta

Show that shortest-duration-first fails on x(0,5), y(4,7), z(6,11).

Cevabı göster
Shortest picks only y (length 3); optimum is x, z (2)

Uzunluklar x=5, y=3, z=5. En kısa y seçilir; y hem x (4 < 5) hem z (6 < 7) ile çakışır, başka bir şey eklenemez. Bitişe göre greedy x(0,5) ve z(6,11) alır.

Soru 5kolay

What is the running time of the earliest-finish greedy for n activities that are not sorted?

Cevabı göster
O(n log n)

Bitişe göre sıralama O(nlog⁡n)O(n \log n), sonra tek tarama O(n)O(n). Toplam O(nlog⁡n)O(n \log n). Girdi zaten sıralıysa O(n)O(n).

Soru 6orta

Fractional knapsack, capacity 15. Items (weight, value): A(6, 30), B(10, 40), C(4, 28), D(8, 24). What is the maximum total value?

Cevabı göster
78

Oranlar (value/weight): C 7, A 5, B 4, D 3. Büyükten küçüğe al:
C tamamı: 4 kg, 28. Kalan 11.
A tamamı: 6 kg, 30, toplam 58. Kalan 5.
B'nin 5/10'u: 40 × 0.5 = 20, toplam 78. Çanta dolu.

Soru 7kolay

Same items, fractional knapsack with capacity 20. Maximum value?

Cevabı göster
98

C (4, 28) + A (6, 30) + B tamamı (10, 40) = 20 kg, 98. Çanta tam doldu, D'ye yer kalmadı.

Soru 8zor

Same items, but now 0/1 knapsack (take an item whole or not at all), capacity 15. What does the greedy-by-ratio rule get, and what is the true optimum?

Cevabı göster
Greedy: C + A = 58; optimum: B + C = 68

Greedy oranla C (4 kg) ve A (6 kg) alır, kalan 5 kg. B (10) ve D (8) sığmaz: 58.
Tüm alt kümeler denenince en iyisi B + C: 14 kg, 68.
0/1 sırt çantasında greedy-choice property yok; çözüm dinamik programlama (O(nW)O(nW)).

Soru 9kolay

Coins {25, 10, 5, 1}. How many coins does the greedy algorithm use for 68, and which ones?

Cevabı göster
7 coins: 25, 25, 10, 5, 1, 1, 1

Her adımda sığan en büyük madeni para: 68 → 43 → 18 → 8 → 3 → 2 → 1 → 0. Bu sistem için greedy optimumdur (DP de 7 buluyor).

Soru 10orta

Coins {1, 4, 6}, amount 8. Greedy result vs optimal?

Cevabı göster
Greedy: 6 + 1 + 1 = 3 coins; optimal: 4 + 4 = 2 coins

Greedy önce 6'yı alır, kalan 2 sadece 1'lerle ödenir. 4 + 4 daha az madeni para. Greedy para üstü her sistemde çalışmaz; sistem 'canonical' olmalı. Genel çözüm DP: dp[a] = min(dp[a-c] + 1).

Soru 11zor

Write a method int maxActivities(int[] s, int[] f) that returns the maximum number of non-overlapping activities (an activity may start when the previous ends). Arrays are not sorted.

Cevabı göster
Sort indices by finish time, then take every activity whose start ≥ last finish

static int maxActivities(int[] s, int[] f) {
    int n = s.length;
    Integer[] idx = new Integer[n];
    for (int i = 0; i < n; i++) idx[i] = i;
    Arrays.sort(idx, (a, b) -> Integer.compare(f[a], f[b]));
    int count = 0, lastFinish = Integer.MIN_VALUE;
    for (int i : idx) {
        if (s[i] >= lastFinish) {
            count++;
            lastFinish = f[i];
        }
    }
    return count;
}
s ve f'yi ayrı ayrı sıralama; çiftler bozulur. İndeksleri sırala. Sayfadaki 9 etkinlikte 5 döner.

Soru 12zor

Write a method double fractionalKnapsack(int[] w, int[] v, int cap) that returns the maximum value when items may be split.

Cevabı göster
Sort by v/w descending; take whole items while they fit, then a fraction of the next

static double fractionalKnapsack(int[] w, int[] v, int cap) {
    int n = w.length;
    Integer[] idx = new Integer[n];
    for (int i = 0; i < n; i++) idx[i] = i;
    Arrays.sort(idx, (a, b) -> Double.compare((double) v[b] / w[b], (double) v[a] / w[a]));
    double total = 0;
    int left = cap;
    for (int i : idx) {
        if (left == 0) break;
        int take = Math.min(left, w[i]);
        total += (double) v[i] * take / w[i];
        left -= take;
    }
    return total;
}
Oranı v[i] / w[i] diye int bölmeyle hesaplarsan bu örnekte oranlar tesadüfen tam sayı çıkar ama 7 kg'lık 25 değerli bir eşyanın oranı 3 olur (3.57 yerine) ve sıralama bozulabilir; double'a çevir. Sayfadaki örnekte 78.0 döner.

Doğrulama: Etkinlik seçimi (bitiş sırasına göre greedy + 2^n kaba kuvvetle optimum), karşı örnekler, kesirli ve 0/1 sırt çantası (greedy + tüm alt kümeleri deneyen kaba kuvvet), para üstü (greedy + DP) verify/SEN2212/W12.java ile çalıştırıldı (java W12.java). Yaz-metot cevapları verify/SEN2212/WMethods11to14.java içinde derlenip test edildi.

Deftere not kartı

GREEDY: her adımda o an en iyi görüneni seç, geri dönme Doğru olması için: greedy-choice property + optimal substructure Yanlış olduğunu göstermek için: TEK karşı örnek yeter Etkinlik seçimi: EN ERKEN BİTENİ al, s >= sonBitiş ise ekle erken başlayan / en kısa / az çakışan kuralları YANLIŞ Süre: sıralama O(n log n) + tarama O(n) Kesirli sırt çantası: v/w oranına göre azalan, son parçayı böl → optimum 0/1 sırt çantası: greedy YANLIŞ, DP O(nW) örnek cap 15: kesirli 78, 0/1 greedy 58, 0/1 optimum 68 Para üstü {25,10,5,1}: greedy optimum (68 → 7 para) {1,4,6} ile 8: greedy 6+1+1=3, optimum 4+4=2 Huffman, Prim, Kruskal, Dijkstra da greedy algoritmalardır