Bölüm 11: Yaklaşım Algoritmaları
Giriş
Öğrenme Çıktıları
Yaklaşım (approximation) algoritmasının ne olduğunu, yaklaşım oranını ve sezgisel yöntemlerden farkını açıklamak.
Gezgin satıcı problemi için en yakın komşu, MST tabanlı 2-yaklaşım ve 2-opt yerel aramasını adım adım uygulamak.
Makine çizelgeleme (liste çizelgeleme, LPT) ve düğüm kapsama 2-yaklaşımını Java ile yazıp izlemek; oranlarını kanıtlamak.
Power Iteration ile en büyük özdeğer ve özvektörün yinelemeli olarak nasıl yakınsandığını hesaplamak.
Giriş
Yaklaşım Algoritmaları (Approximation Algorithms)
- Bazı problemlerin kesin (optimal) çözümünü bulmak çok zor ya da pratikte imkânsız olabilir: TSP, düğüm kapsama, makine çizelgeleme ve sırt çantası NP-zordur; P ≠ NP ise polinom zamanlı kesin algoritmaları yoktur.
- Yaklaşım algoritmaları mükemmel çözümü aramak yerine, optimal çözüme mümkün olduğunca yakın çözümler üretir.
- Polinom zamanda çalışırlar: karmaşık problemler makul sürede çözülebilir.
- Çözümün optimal çözüme belli bir oran ya da yüzde içinde yakın olduğu çoğu zaman kanıtlanabilir.
- Hesaplama kaynakları (zaman, bellek) kısıtlı olduğunda tercih edilir.
Giriş
Terazi Benzetmesi
- Terazinin bir kefesine bir ağırlık konduğunda, diğer kefeye tam olarak aynı ağırlığı koymak zor olabilir.
- Bu durumda, eldeki çeşitli küçük ağırlıklar kullanılarak büyük ağırlığa olabildiğince yakın bir denge kurulur.
- Elimizde yalnızca 20, 10, 5 ve 1 kg varsa ve her biri bir kez kullanılabiliyorsa, 37 kg'a en yakın denge 36 kg'dır.
Giriş
Yaklaşım Oranı (Approximation Ratio)
C: algoritmanın bulduğu çözümün maliyeti, C*: optimal çözümün maliyeti. Algoritma her girdi için
koşulunu sağlıyorsa bir ρ(n)-yaklaşım algoritmasıdır (ρ ≥ 1; ρ = 1 ise algoritma optimaldir).
Oran bir en kötü durum garantisidir; pratikte çözümler çoğu zaman optimuma çok daha yakındır.
Giriş
Yaklaşım Algoritması, Sezgisel ve Yaklaşım Şemaları
| Yaklaşım | Garanti | Örnek |
|---|---|---|
| Kesin algoritma | Optimal; ama NP-zor problemlerde üstel zaman | Kaba kuvvet TSP: (n−1)!/2 tur |
| Yaklaşım algoritması | Polinom zaman + kanıtlanmış oran ρ | Düğüm kapsama: ρ = 2 |
| PTAS | Her sabit ε > 0 için (1 + ε) oranı, n'de polinom (ε'da üstel olabilir) | Öklid TSP (Arora, 1998) |
| FPTAS | (1 + ε) oranı, hem n'de hem 1/ε'da polinom | Sırt çantası: O(n³/ε) |
| Sezgisel (heuristic) | Garanti yok; pratikte genellikle iyi | 2-opt, en yakın komşu |
| Metasezgisel | Garanti yok; problemden bağımsız arama çerçevesi | Genetik algoritma, karınca kolonisi |
Rastgele yuvarlama (randomized rounding) gibi rastgele yaklaşım algoritmaları da vardır; beklenen değerde bir oran garanti ederler.
Giriş
Yaklaşım Algoritmalarının Uygulamaları
Satıcının tüm müşterilere en kısa toplam yolla uğrayıp geri döndüğü rotaya karar vermek: lojistik, kargo, devre kartı delme.
Çantaya sığacak ve en büyük faydayı sağlayacak eşyaları seçmek: bütçe, yük ve portföy planlama.
Birden fazla işin ya da sürecin makinelerde/işlemcilerde en verimli şekilde yürütülmesi.
Ağlara en az sayıda izleme noktası yerleştirmek; büyük matrislerin özdeğerini yinelemeli yakınsamak (PageRank).
Giriş
Yaklaşım Algoritmalarının Türleri
Problemin daha basit bir sürümü çözülür (ör. tam sayı kısıtı gevşetilir: LP gevşetmesi, MST ile TSP alt sınırı).
Her adımda o an en iyi görünen seçenek seçilerek ilerlenir (en yakın komşu, LPT, oran sıralı sırt çantası).
Mevcut çözüm küçük değişikliklerle iyileştirilir; daha iyi komşu kalmayınca durulur (2-opt).
Gezgin Satıcı
Gezgin Satıcı Problemi (TSP)
- En iyileme problemi: satıcı, bir dizi şehri en kısa toplam uzaklıkta birer kez ziyaret edip başladığı şehre dönmek ister.
- Kombinatoryal problem: çözüm, tüm şehirlerin gezilme sırasıdır (bir permütasyon).
- NP-zor: çok sayıda şehir için en iyi rotayı bulmak pratikte zordur. İki düğüm arasındaki en kısa yol (Dijkstra) ise polinom zamanda çözülür; iki problem karıştırılmamalıdır.
- Girdi: n şehir (0, 1, 2, … ya da A, B, C, …) ve dij: i ve j şehirleri arasındaki uzaklık.
- Simetrik TSP: dij = dji; çizge kuramında: tam çizgedeki en hafif Hamilton çevrimi.
| d | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| 0 | 0 | 10 | 15 | 20 | 25 |
| 1 | 10 | 0 | 35 | 25 | 30 |
| 2 | 15 | 35 | 0 | 30 | 35 |
| 3 | 20 | 25 | 30 | 0 | 40 |
| 4 | 25 | 30 | 35 | 40 | 0 |
Örnek: 5 şehrin uzaklık matrisi.
Gezgin Satıcı
Problemin Çözümü
| n | (n−1)!/2 farklı tur |
|---|---|
| 5 | 12 |
| 10 | 181 440 |
| 15 | ≈ 4,4 · 1010 |
| 20 | ≈ 6,1 · 1016 |
| 25 | ≈ 3,1 · 1023 |
Başlangıç şehri sabitlenir ve iki yön aynı sayılır. Saniyede 10⁹ tur denense bile n = 25 için ≈ 10⁷ yıl gerekir.
Gezgin Satıcı
En Yakın Komşu (Nearest Neighbor) Sezgiseli
- Bir başlangıç şehri seç; onu ziyaret edildi olarak işaretle.
- Bulunduğun şehirden ziyaret edilmemiş en yakın şehre git (açgözlü seçim).
- Tüm şehirler ziyaret edilene kadar 2. adımı tekrarla.
- Son şehirden başlangıç şehrine dön ve turu kapat.
Artıları
- Çok basit; O(n²) zaman.
- Genellikle optimumun %25 kadar üzerinde tur verir.
- Yerel arama için iyi bir başlangıç turu.
Eksileri
- Sabit bir yaklaşım oranı yoktur; metrik TSP'de bile oran Θ(log n) olabilir.
- Son dönüş kenarı çok uzun kalabilir.
Gezgin Satıcı · Kodu adım adım çalıştır
En Yakın Komşu: Kodu Adım Adım İzle
Başlangıç şehri 0: ziyaret[0] = true, tur = [0], toplam = 0.
0. satır taranır, ziyaret edilmemişler: d[0][1] = 10, d[0][2] = 15, d[0][3] = 20, d[0][4] = 25 → en küçüğü 1 (10).
tur[1] = 1, toplam += 10 → 10; artık simdiki = 1.
1. satır taranır, ziyaret edilmemişler: d[1][2] = 35, d[1][3] = 25, d[1][4] = 30 → en küçüğü 3 (25).
tur[2] = 3, toplam += 25 → 35; artık simdiki = 3.
3. satır taranır, ziyaret edilmemişler: d[3][2] = 30, d[3][4] = 40 → en küçüğü 2 (30).
tur[3] = 2, toplam += 30 → 65; artık simdiki = 2.
2. satır taranır, ziyaret edilmemişler: d[2][4] = 35 → en küçüğü 4 (35).
tur[4] = 4, toplam += 35 → 100; artık simdiki = 4.
Tüm şehirler ziyaret edildi; başlangıca dönülür: toplam += d[4][0] = 25 → 125.
Tur 0 → 1 → 3 → 2 → 4 → 0, uzunluk 125. (Kaba kuvvetle doğrulandı: bu örnekte optimumdur.)
int[] enYakinKomsu(int[][] d, int bas) { int n = d.length, toplam = 0, simdiki = bas; boolean[] ziyaret = new boolean[n]; int[] tur = new int[n + 1]; tur[0] = bas; ziyaret[bas] = true; for (int k = 1; k < n; k++) { int enYakin = -1, enAz = Integer.MAX_VALUE; for (int j = 0; j < n; j++) if (!ziyaret[j] && d[simdiki][j] < enAz) { enAz = d[simdiki][j]; enYakin = j; } // en yakın şehre git tur[k] = enYakin; ziyaret[enYakin] = true; toplam += enAz; simdiki = enYakin; } // başlangıca dön tur[n] = bas; toplam += d[simdiki][bas]; return tur; }
Gezgin Satıcı
Kaba Kuvvetle Karşılaştırma: 12 Farklı Tur
| Tur | Uzunluk |
|---|---|
| 0 → 1 → 3 → 2 → 4 → 0 | 125 |
| 0 → 1 → 3 → 4 → 2 → 0 | 125 |
| 0 → 1 → 4 → 2 → 3 → 0 | 125 |
| 0 → 1 → 4 → 3 → 2 → 0 | 125 |
| 0 → 2 → 3 → 1 → 4 → 0 | 125 |
| 0 → 2 → 4 → 1 → 3 → 0 | 125 |
| Tur | Uzunluk |
|---|---|
| 0 → 1 → 2 → 3 → 4 → 0 | 140 |
| 0 → 1 → 2 → 4 → 3 → 0 | 140 |
| 0 → 2 → 1 → 3 → 4 → 0 | 140 |
| 0 → 2 → 1 → 4 → 3 → 0 | 140 |
| 0 → 3 → 1 → 2 → 4 → 0 | 140 |
| 0 → 3 → 2 → 1 → 4 → 0 | 140 |
- (5−1)!/2 = 12 tur denendi: optimum 125; en yakın komşu da 125 buldu (bu örnek için şanslı bir durum).
- Bu matris üçgen eşitsizliğini sağlamaz: d12 = 35 > d10 + d02 = 10 + 15. Yani örnek metrik değildir.
Gezgin Satıcı
Üçgen Eşitsizliği ve Yaklaşım Sınırları
| Durum | Oran | Açıklama |
|---|---|---|
| Genel TSP | yok | P ≠ NP ise hiçbir sabit ρ için polinom zamanlı ρ-yaklaşım yoktur: böyle bir algoritma Hamilton çevrimi problemini çözerdi. |
| Metrik TSP, MST tabanlı | 2 | MST + önce-kök (preorder) gezinme + kısayol; O(n²). |
| Metrik TSP, Christofides | 1,5 | MST + tek dereceli düğümlerde en küçük mükemmel eşleştirme + Euler turu (1976). |
| Öklid TSP | 1 + ε | Düzlemdeki noktalar için PTAS vardır (Arora, Mitchell). |
| En yakın komşu | Θ(log n) | Metrik durumda bile sabit oran garanti etmez. |
Gezgin Satıcı
Metrik TSP için MST Tabanlı 2-Yaklaşım
Metrik örnek: düzlemde 7 şehir; uzaklıklar Öklid uzaklığıdır (üçgen eşitsizliği sağlanır).
1) Prim ile minimum kapsayan ağaç (MST) kurulur: toplam ağırlık w(T) = 228,8. Bir turdan bir kenar silinince kapsayan ağaç kalır → w(T) ≤ OPT.
2) Ağaç A'dan derinlik öncelikli iki kez gezilir (her kenar bir gidiş bir dönüş): A → D → B → C → E → F → E → C → B → D → G → D → A. Uzunluk 2 · w(T) = 457,6.
3) Tekrar eden şehirler atlanır (kısayol): önce-kök sırası A → D → B → C → E → F → G → A. Üçgen eşitsizliği sayesinde kısayol yolu uzatmaz: tur = 287,7.
Sonuç: tur ≤ 2 · w(T) ≤ 2 · OPT. Burada tur = 287,7, optimum (kaba kuvvet, 360 tur) = 282,5 → oran 1,02 ≤ 2.
Yerel Arama
Yerel Arama: 2-opt Hamlesi
Önce: (a, b) ve (c, d) kenarları çaprazlanıyor.
Sonra: (a, c) ve (b, d); aradaki yol ters çevrildi.
- Turdan iki kenar çıkar, uçları çapraz bağla: b … c arasındaki alt yol ters çevrilir.
- Kazanç Δ = d(a,c) + d(b,d) − d(a,b) − d(c,d) < 0 ise hamle yapılır. Öklid düzleminde her kesişme böyle kaldırılabilir.
- İyileştiren hamle kalmayınca tur 2-opt yerel optimumudur (genel optimum olması gerekmez).
Yerel Arama · Adım adım
2-opt ile Turu İyileştirme
28 şehir, rastgele başlangıç turu: uzunluk 1269,8. Kenarlar sürekli birbirini kesiyor.
1. iyileştiren hamleden sonra: (a,b), (c,d) çıkarıldı (kesikli), (a,c), (b,d) eklendi (kalın). Δ = −36,9 → uzunluk 1232,9.
2. iyileştiren hamleden sonra: (a,b), (c,d) çıkarıldı (kesikli), (a,c), (b,d) eklendi (kalın). Δ = −8,9 → uzunluk 1224,0.
4. iyileştiren hamleden sonra: (a,b), (c,d) çıkarıldı (kesikli), (a,c), (b,d) eklendi (kalın). Δ = −27,6 → uzunluk 1187,3.
8. iyileştiren hamleden sonra: (a,b), (c,d) çıkarıldı (kesikli), (a,c), (b,d) eklendi (kalın). Δ = −32,6 → uzunluk 1111,7.
14. iyileştiren hamleden sonra: (a,b), (c,d) çıkarıldı (kesikli), (a,c), (b,d) eklendi (kalın). Δ = −14,9 → uzunluk 1005,2.
22. iyileştiren hamleden sonra: (a,b), (c,d) çıkarıldı (kesikli), (a,c), (b,d) eklendi (kalın). Δ = −37,0 → uzunluk 852,8.
32. iyileştiren hamleden sonra: (a,b), (c,d) çıkarıldı (kesikli), (a,c), (b,d) eklendi (kalın). Δ = −11,8 → uzunluk 595,9.
48. ve son hamle: artık hiçbir 2-opt hamlesi turu kısaltmıyor → yerel optimum, uzunluk 430,8 (başlangıcın %34'ü). Kesişen kenar kalmadı.
Yerel Arama
2-opt Yerel Arama: Java
void ikiOpt(int[] tur, double[][] d) { int n = tur.length; boolean iyilesti = true; while (iyilesti) { iyilesti = false; for (int i = 0; i < n - 1; i++) for (int j = i + 2; j < n; j++) { int a = tur[i], b = tur[i + 1]; int c = tur[j], e = tur[(j + 1) % n]; double fark = d[a][c] + d[b][e] - d[a][b] - d[c][e]; if (fark < -1e-9) { // kısalıyor tersCevir(tur, i + 1, j); iyilesti = true; } } } }
Yerel Arama · Kodu adım adım çalıştır
2-opt: Kodu Adım Adım İzle
Başlangıç turu 0 → 1 → 2 → 3 → 0, uzunluk 18. (0, 1) ve (2, 3) kenarları çaprazlanıyor.
Tarama 1 başlar: iyilesti = false. Bu taramada hiç hamle yapılmazsa döngü biter.
i = 0, j = 2: (0,1) ve (2,3) yerine (0,2) ve (1,3). fark = 3 + 3 − 5 − 5 = −4 < 0 → tur kısalır.
tersCevir(tur, 1, 2): aradaki yol ters çevrilir → [0, 2, 1, 3], uzunluk 14. iyilesti = true.
i = 0, j = 3: fark = 4 + 3 − 3 − 4 = 0 (iki kenar komşu: e = a) → hamle yapılmaz.
i = 1, j = 3: fark = 5 + 5 − 4 − 4 = 2 → hamle yapılmaz.
Önceki taramada hamle yapıldı (iyilesti = true), tarama baştan yinelenir.
i = 0, j = 2: fark = 5 + 5 − 3 − 3 = 4 → hamle yapılmaz.
i = 0, j = 3: fark = 4 + 3 − 3 − 4 = 0 (iki kenar komşu: e = a) → hamle yapılmaz.
i = 1, j = 3: fark = 5 + 5 − 4 − 4 = 2 → hamle yapılmaz.
Tüm tarama boyunca kısalma bulunmadı: döngü biter. Tur [0, 2, 1, 3], uzunluk 14: 2-opt yerel optimumu (bu 4 noktada aynı zamanda optimum).
void ikiOpt(int[] tur, double[][] d) { int n = tur.length; boolean iyilesti = true; while (iyilesti) { iyilesti = false; for (int i = 0; i < n - 1; i++) for (int j = i + 2; j < n; j++) { int a = tur[i], b = tur[i + 1]; int c = tur[j], e = tur[(j + 1) % n]; double fark = d[a][c] + d[b][e] - d[a][b] - d[c][e]; if (fark < -1e-9) { // kısalıyor tersCevir(tur, i + 1, j); iyilesti = true; } } } }
Yerel Arama
Yerel Optimumdan Kaçış: Metasezgiseller
(Simulated annealing) Kötüleştiren bir hamle de e−Δ/T olasılıkla kabul edilir; "sıcaklık" T yavaşça düşürülür. Yerel optimumdan çıkabilir.
Turlardan oluşan bir popülasyon; seçilim, çaprazlama (crossover) ve mutasyonla nesiller boyunca iyileştirilir.
(Ant colony optimization) Karıncalar kısa turların kenarlarına daha çok feromon bırakır; sonraki karıncalar feromonu yoğun kenarları tercih eder.
- Üçü de TSP, araç rotalama, iş çizelgeleme ve atama problemlerinde yaygındır.
- Hiçbiri yaklaşım oranı garanti etmez; sonuç başlangıç çözümüne ve parametrelere duyarlıdır. Tipik ayarlar: T₀ = 100, her adımda T ← 0,997 · T; 100 bireylik popülasyon, rastgele kesim noktalı çaprazlama, 0,05 mutasyon olasılığı.
Yalnızca iyileştiren hamleleri kabul eden yerel arama soldaki çukurda kalır. Benzetimli tavlama yüksek T'de tepeyi aşabilir; T düştükçe hamleler seçicileşir.
İş Çizelgeleme
İş Çizelgeleme (Job Scheduling)
- En iyileme problemi: belirli kaynaklarla (işçiler, makineler, işlemciler) işlerin en verimli şekilde planlanması.
- Amaç: işlerin tamamlanma süresini en aza indirmek ya da belirli ölçütlere (kâr, gecikme, son tarih) göre en iyilemek.
n iş, m özdeş makine; iş j'nin süresi pj. Son işin bittiği an Cmax (en büyük yük, makespan) en küçük olsun. m ≥ 2 için NP-zor.
Her iş 1 birim sürer, bir kârı ve son tarihi (deadline) vardır. Son tarihinden önce biten işlerin toplam kârı en büyük olsun.
İlk problem için açgözlü yaklaşım algoritmaları (liste çizelgeleme, LPT) vardır; ikincisi açgözlü bir algoritmayla optimal çözülür.
İş Çizelgeleme · Adım adım
Makinelere İş Atama: Liste Çizelgeleme
Üç özdeş makine M1–M3. İşler sırayla gelir: J1 (2), J2 (8), J3 (6) t = 0'da hazır; J4 (3) t = 3'te gelir. Liste çizelgeleme (Graham): sıradaki iş, ilk boşalan makineye atanır.
J1 (süre 2) → M1, [0, 2] aralığında çalışır (tüm makineler boş; ilk makine seçilir).
J2 (süre 8) → M2, [0, 8] aralığında çalışır (M1 t = 2 anına kadar meşgul).
J3 (süre 6) → M3, [0, 6] aralığında çalışır (M1 t = 2 anına kadar meşgul; M2 t = 8 anına kadar meşgul).
t = 2: M1 boşaldı ama bekleyen iş yok; makine t = 3'e kadar boşta kalır (taralı alan).
J4 (süre 3) → M1, [3, 6] aralığında çalışır (M2 t = 8 anına kadar meşgul; M3 t = 6 anına kadar meşgul).
Tüm işler atandı: Cmax = 8 (M2). Alt sınır: OPT ≥ en uzun iş = 8 → bu çizelge optimaldir. Genelde ise liste çizelgeleme yalnızca (2 − 1/m) oranını garanti eder.
İş Çizelgeleme
Liste Çizelgeleme: (2 − 1/m)-Yaklaşım
İki alt sınır: OPT ≥ Σpj / m (iş yükü paylaştırılmalı) ve OPT ≥ max pj.
- En son biten iş j, sj anında başlamış olsun.
- sj'den önce tüm makineler meşguldü (yoksa j daha erken başlardı) → sj ≤ (Σp − pj) / m.
- Cmax = sj + pj ≤ Σp / m + (1 − 1/m) · pj ≤ OPT + (1 − 1/m) · OPT.
• Liste: M1 = 1 + 2 = 3, M2 = 1 → Cmax = 3
• Optimum: {1, 1} ve {2} → 2
Oran 3/2 = 2 − 1/2.Genelde m(m − 1) adet 1 birimlik iş ve sonda tek bir m birimlik iş oranı 2 − 1/m'ye ulaştırır.
İş Çizelgeleme
En Uzun İş Önce (LPT): 4/3-Yaklaşım
LPT (Longest Processing Time first): işleri süreye göre azalan sırala, sonra liste çizelgeleme uygula. İşler: 2, 3, 4, 6, 2, 2 ve m = 3.
Verilen sıra: Cmax = 8
LPT sırası 6, 4, 3, 2, 2, 2: Cmax = 7 = OPT (≥ ⌈19/3⌉ = 7)
- Uzun işler başa alınınca sona kalan kısa işler dengesizliği düzeltir: Cmax ≤ (4/3 − 1/(3m)) · OPT (Graham, 1969). Süre O(n log n).
- Sıkı örnek (m = 3): 5, 5, 4, 4, 3, 3, 3 → LPT 11, optimum 9 ({5, 4}, {5, 4}, {3, 3, 3}).
İş Çizelgeleme · Kodu adım adım çalıştır
LPT Çizelgeleme: Kodu Adım Adım İzle
İşler 2, 3, 4, 6, 2, 2 ve m = 3 makine. Bu sırayla doğrudan liste çizelgeleme Cmax = 8 verir.
LPT: işler süreye göre azalan sıralanır → 6, 4, 3, 2, 2, 2.
Üç makinenin yükü de 0. Her iş, o an en az yüklü makineye gidecek.
p = 6: en az yüklü makine k = 0 (yük 0) (eşitlikte < ilk makinede kalır) → yuk = [6, 0, 0].
p = 4: en az yüklü makine k = 1 (yük 0) → yuk = [6, 4, 0].
p = 3: en az yüklü makine k = 2 (yük 0) → yuk = [6, 4, 3].
p = 2: en az yüklü makine k = 2 (yük 3) → yuk = [6, 4, 5].
p = 2: en az yüklü makine k = 1 (yük 4) → yuk = [6, 6, 5].
p = 2: en az yüklü makine k = 2 (yük 5) → yuk = [6, 6, 7].
En büyük yük Cmax = 7. Alt sınır ⌈19/3⌉ = 7 olduğundan bu çizelge optimaldir.
int lpt(Integer[] isler, int m) { Arrays.sort(isler, Comparator.reverseOrder()); int[] yuk = new int[m]; for (int p : isler) { int k = 0; // en az yüklü for (int i = 1; i < m; i++) if (yuk[i] < yuk[k]) k = i; yuk[k] += p; } return Arrays.stream(yuk).max().getAsInt(); }
Düğüm Kapsama
Düğüm Kapsama (Vertex Cover)
- Kapsama problemi: bir çizgenin tüm kenarlarını kapsayacak en az sayıda düğümü seçmek. Bir kenar, uçlarından en az biri seçilmişse kapsanır.
- Amaç: tüm kenarları en az düğümle kapsayan C ⊆ V kümesini bulmak. Karar sürümü ("k düğümlük kapsama var mı?") NP-tamdır.
Geçerli bir kapsama, boyut 6 (her kenarı bir "gözcü" görüyor)
Aynı çizgede en küçük kapsama, boyut 3
Düğüm Kapsama
Örnek: Dört Düğümlü Çizge
- Düğümler: A, B, C, D
- Kenarlar: (A, B), (A, C), (B, C), (B, D), (C, D)
- {A, B, C} bir düğüm kapsama kümesidir: her kenarın en az bir ucu kümede.
- Ama en küçük değildir: {B, C} de beş kenarın hepsini kapsar.
- Tek düğüm yetmez (B, (A, C)'yi kapsamaz) → optimum 2.
{A, B, C}: geçerli, boyut 3
{B, C}: en küçük, boyut 2
Düğüm Kapsama
Düğüm Kapsama: Çözüm Yaklaşımları
En küçük kapsama {A, B, H, I, J} (5 düğüm)
Düğüm Kapsama
Düğüm Kapsama Algoritması
Saf fikir:
- Başlangıçta boş bir kapsama kümesi oluştur.
- Kapsanmamış bir kenar seç; uçlarından birini kümeye ekle.
- Tüm kenarlar kapsanana kadar tekrarla.
Uçlardan yalnızca birini eklemek garanti vermez. Doğru 2-yaklaşım:
- Kapsanmamış bir (u, v) kenarı seç; u ve v'nin ikisini de ekle.
- u ya da v'ye değen tüm kenarları kapsanmış say; kenar kalmayana kadar tekrarla.
Her kenarda yaprak ucu seçilirse 5 düğüm; optimum {m}, 1 düğüm. n yapraklı yıldızda oran n olur.
Düğüm Kapsama · Kodu adım adım çalıştır
Düğüm Kapsama 2-Yaklaşımı: Kodu Adım Adım İzle
Kapsama kümesi boş. Kenarlar sırayla gezilecek: (A,B), (A,C), …, (J,L).
(A, B): iki uç da kapsamada değil → A ve B eklenir. Bu kenarlar bir eşleştirme (matching) oluşturur.
(A, C): A zaten kapsamada → kenar kapsanmış, atlanır.
(A, D): A zaten kapsamada → kenar kapsanmış, atlanır.
(A, E): A zaten kapsamada → kenar kapsanmış, atlanır.
(A, F): A zaten kapsamada → kenar kapsanmış, atlanır.
(B, C): B zaten kapsamada → kenar kapsanmış, atlanır.
(G, H): iki uç da kapsamada değil → G ve H eklenir. Bu kenarlar bir eşleştirme (matching) oluşturur.
(G, I): G zaten kapsamada → kenar kapsanmış, atlanır.
(H, I): H zaten kapsamada → kenar kapsanmış, atlanır.
(H, K): H zaten kapsamada → kenar kapsanmış, atlanır.
(I, J): iki uç da kapsamada değil → I ve J eklenir. Bu kenarlar bir eşleştirme (matching) oluşturur.
(J, K): J zaten kapsamada → kenar kapsanmış, atlanır.
(J, L): J zaten kapsamada → kenar kapsanmış, atlanır.
Sonuç {A, B, G, H, I, J}: 6 düğüm. Optimum 5 ({A, B, H, I, J}) → oran 6/5 = 1,2 ≤ 2.
Set<Character> dugumKapsama(char[][] kenarlar) { Set<Character> kapsama = new HashSet<>(); for (char[] k : kenarlar) { char u = k[0], v = k[1]; if (!kapsama.contains(u) && !kapsama.contains(v)) { kapsama.add(u); kapsama.add(v); } // iki uç } return kapsama; }
Düğüm Kapsama
Neden En Fazla 2 × Optimum?
- Algoritmanın seçtiği kenarlar M kümesi olsun. Seçilen her kenarın iki ucu da eklendiği için M'deki kenarların ortak ucu yoktur (M bir eşleştirmedir).
- Her kapsama, M'deki her kenarı kapsamak için farklı bir düğüm içermek zorundadır → OPT ≥ |M|.
- Algoritma tam olarak |C| = 2 |M| düğüm seçer → |C| ≤ 2 · OPT.
2'den belirgin biçimde iyi bir sabit oran bilinmiyor; 2 − ε oranının (Benzersiz Oyunlar Varsayımı altında) imkânsız olduğu gösterilmiştir.
Düğüm Kapsama · Adım adım
NP-Tamlık: 3-SAT'tan Düğüm Kapsamaya İndirgeme
φ = (x₁ ∨ x₁ ∨ x₂) ∧ (¬x₁ ∨ ¬x₂ ∨ ¬x₂) ∧ (¬x₁ ∨ x₂ ∨ x₂). Her değişken için bir kenar (üst kutu), her tümce için bir üçgen; tümcedeki her literal aynı adlı değişken düğümüne bağlanır. l = 2 değişken, m = 3 tümce → k = l + 2m = 8.
Atama x₁ = yanlış: değişken kenarından ¬x₁ seçilir. Kapsanan kenarlar soluklaşır.
Atama x₂ = doğru: x₂ seçilir. Her değişken kenarı tam olarak bir düğümle kapsandı (l = 2 düğüm).
C₁'de doğru literal x₂ (bağlantı kenarı zaten kapsanmış) dışarıda bırakılır; diğer iki düğüm (x₁, x₁) eklenir.
C₂'de doğru literal ¬x₁ dışarıda; ¬x₂ ve ¬x₂ düğümleri eklenir.
C₃'te doğru literal ¬x₁ dışarıda; x₂ ve x₂ eklenir. 8 düğüm, 20 kenarın hepsi kapsandı: φ sağlanabilir ⇔ k = l + 2m boyutlu kapsama var.
Sırt Çantası
Sırt Çantası: Oran Sıralı Açgözlü Yaklaşım
| Eşya | Değer | Ağırlık | Oran | Kapasite 10 |
|---|---|---|---|---|
| 6 | 20 | 7 | 2,86 | ✓ alındı (ağırlık 7) |
| 3 | 8 | 4 | 2,00 | ✗ sığmaz |
| 7 | 15 | 8 | 1,88 | ✗ sığmaz |
| 2 | 5 | 3 | 1,67 | ✓ alındı (ağırlık 10) |
| 5 | 10 | 6 | 1,67 | ✗ sığmaz |
| 1 | 3 | 2 | 1,50 | ✗ sığmaz |
| 4 | 6 | 5 | 1,20 | ✗ sığmaz |
Açgözlü toplam değer 25; DP ile optimum da 25 (eşya 2 + 6).
- Eşyaları değer/ağırlık oranına göre azalan sırala; sığanı al. O(n log n).
- Kesirli sırt çantasında bu kural optimaldir; 0/1 sürümde ise garanti yoktur.
- Kötü örnek: W = 10, (değer 2, ağırlık 1) ve (değer 10, ağırlık 10). Açgözlü 2 alır, optimum 10: oran W kadar büyüyebilir.
- İyileştirilmiş kural: max(açgözlü değer, sığan en değerli tek eşya) → 2-yaklaşım (optimumun en az yarısı).
- Daha iyisi: değerleri ölçekleyip DP uygulayan FPTAS, (1 − ε) · OPT, O(n³/ε).
Power Iteration
Power Iteration (Kuvvet Yinelemesi) Algoritması
- Bir matrisin en büyük (mutlak değeri en büyük, baskın) özdeğerini λ1 ve buna ait bir özvektörü v1 yaklaşık olarak hesaplayan yinelemeli bir yöntemdir.
- Tüm özdeğerleri kesin olarak hesaplamak (O(n³)) yerine, yalnızca baskın özdeğer ve özvektörün yaklaşık bir tahminini verir.
- Her adım yalnızca bir matris–vektör çarpımıdır (O(n²), seyrek matriste O(sıfır olmayan öğe)): büyük boyutlu matrislerde etkilidir.
A = [[2, 0], [0, 1]], x₀ = (1, 1): xk ∝ (2k, 1). Her çarpımda v₁ bileşeni 2 kat, öteki 1 kat büyür; normalleştirilmiş vektör adım adım v₁ = (1, 0) yönüne döner (hata ∝ (1/2)k).
Power Iteration
Power Iteration: Adımlar ve Neden Çalışır?
- Bir A matrisi belirlenir ve rastgele (sıfır olmayan) bir başlangıç vektörü x0 seçilir.
- Vektör matrisle çarpılarak yeni vektör elde edilir: y = A · xk.
- Yeni vektörün normu (uzunluğu) 1'e normalleştirilir: xk+1 = y / ‖y‖.
- Bu işlem istenen sayıda ya da değişim küçülene kadar tekrarlanır.
- xk → v1; özdeğer tahmini Rayleigh bölümü λ ≈ xkT A xk.
Neden? x0 = c1v1 + c2v2 + … ise
- |λ2/λ1| < 1 olduğundan diğer bileşenler geometrik olarak söner.
- Hata her adımda ≈ |λ2/λ1| katına iner: oran 1'e yakınsa yakınsama yavaştır.
- Koşul: c1 ≠ 0 (x0, v1'e dik olmamalı) ve |λ1| > |λ2|.
Power Iteration · Adım adım
Power Iteration Adım Adım
A = [[2, 1], [1, 3]], özdeğerler λ₁ = (5 + √5)/2 ≈ 3,618 ve λ₂ ≈ 1,382. Başlangıç x₀ = (1, 0); hata ‖x₀ − v₁‖ = 0,974.
k = 1: A·x = (2,000, 1,000), normalleştir → x = (0,894, 0,447); λ ≈ 3,000, hata 0,5465.
k = 2: A·x = (2,236, 2,236), normalleştir → x = (0,707, 0,707); λ ≈ 3,500, hata 0,2313.
k = 3: A·x = (2,121, 2,828), normalleştir → x = (0,600, 0,800); λ ≈ 3,600, hata 0,0899.
k = 4: x = (0,5547, 0,8321); λ ≈ 3,61538; hata 3,4 · 10⁻². Her adımda ≈ λ₂/λ₁ ≈ 0,38 katına iner.
k = 5: x = (0,5369, 0,8437); λ ≈ 3,61765; hata 1,3 · 10⁻². Her adımda ≈ λ₂/λ₁ ≈ 0,38 katına iner.
k = 6: x = (0,5300, 0,8480); λ ≈ 3,61798; hata 5,0 · 10⁻³. Her adımda ≈ λ₂/λ₁ ≈ 0,38 katına iner.
k = 7: x = (0,5274, 0,8496); λ ≈ 3,61803; hata 1,9 · 10⁻³. Her adımda ≈ λ₂/λ₁ ≈ 0,38 katına iner.
k = 8: x = (0,5264, 0,8503); λ ≈ 3,61803; hata 7,3 · 10⁻⁴. Her adımda ≈ λ₂/λ₁ ≈ 0,38 katına iner.
k = 9: x ≈ (0,5260, 0,8505) ≈ v₁ = (0,5257; 0,8507), λ ≈ 3,618034; hata ≈ 2,8 · 10⁻⁴. Hata grafiği log ölçekte bir doğru: doğrusal (geometrik) yakınsama.
Power Iteration
Power Iteration: Java ve Bir 3 × 3 Örnek
double[] kuvvet(double[][] a, int adim) { int n = a.length; double[] x = new double[n]; Arrays.fill(x, 1.0); // x₀ ≠ 0 for (int k = 0; k < adim; k++) { double[] y = new double[n]; for (int i = 0; i < n; i++) // y = A·x for (int j = 0; j < n; j++) y[i] += a[i][j] * x[j]; double norm = 0; for (double yi : y) norm += yi * yi; norm = Math.sqrt(norm); for (int i = 0; i < n; i++) // ‖x‖ = 1 x[i] = y[i] / norm; } return x; }
Örnek matris (satırlar):
(0,511 0,32 0,12) · (0,211 0,62 0,12) · (0,311 0,12 0,16); x₀ = (1, 1, 1)
| k | x₁ | x₂ | x₃ | ‖A·x‖ |
|---|---|---|---|---|
| 1 | 0,6474 | 0,6474 | 0,4023 | 1,4690 |
| 2 | 0,6533 | 0,6533 | 0,3827 | 0,8974 |
| 3 | 0,6539 | 0,6539 | 0,3807 | 0,9005 |
| 4 | 0,6539 | 0,6539 | 0,3805 | 0,9008 |
| 5 | 0,6539 | 0,6539 | 0,3805 | 0,9008 |
| 6 | 0,6539 | 0,6539 | 0,3805 | 0,9008 |
| 8 | 0,6539 | 0,6539 | 0,3805 | 0,9008 |
‖A·x‖ → λ₁ = 0,9008; v₁ ∝ (0,6539; 0,6539; 0,3805). λ₂/λ₁ = 0,3/0,9008 ≈ 0,33 → hızlı yakınsama.
Power Iteration · Kodu adım adım çalıştır
Power Iteration: Kodu Adım Adım İzle
Başlangıç vektörü x₀ = (1, 1, 1). v₁'e dik olmayan, sıfırdan farklı her vektör olur.
y[0] = A'nın 0. satırı · x = 0,511·1 + 0,32·1 + 0,12·1 = 0,9510.
y[1] = A'nın 1. satırı · x = 0,211·1 + 0,62·1 + 0,12·1 = 0,9510.
y[2] = A'nın 2. satırı · x = 0,311·1 + 0,12·1 + 0,16·1 = 0,5910.
‖y‖ = √(0,9510² + 0,9510² + 0,5910²) = 1,4690.
x = y / ‖y‖ = (0,6474; 0,6474; 0,4023): uzunluğu 1 olan yeni yön; sayılar ne büyür ne söner.
k = 1: y = A·x = (0,5862; 0,5862; 0,3434). Bileşenlerin oranı neredeyse aynı kaldı.
‖y‖ = 0,8974 → x = (0,6533; 0,6533; 0,3827). Yön çok az değişti.
k = 2: y = A·x = (0,5888; 0,5888; 0,3428). Bileşenlerin oranı neredeyse aynı kaldı.
‖y‖ = 0,9005 → x = (0,6539; 0,6539; 0,3807). ‖y‖, λ₁ = 0,9008 değerine yaklaşıyor.
adim = 3 yineleme bitti: x ≈ v₁ = (0,6539; 0,6539; 0,3807). Sonraki yinelemelerde dört basamak artık değişmez.
double[] kuvvet(double[][] a, int adim) { int n = a.length; double[] x = new double[n]; Arrays.fill(x, 1.0); // x₀ ≠ 0 for (int k = 0; k < adim; k++) { double[] y = new double[n]; for (int i = 0; i < n; i++) // y = A·x for (int j = 0; j < n; j++) y[i] += a[i][j] * x[j]; double norm = 0; for (double yi : y) norm += yi * yi; norm = Math.sqrt(norm); for (int i = 0; i < n; i++) // ‖x‖ = 1 x[i] = y[i] / norm; } return x; }
Power Iteration
Power Iteration: Sınırlar ve Uygulamalar
Güçlü yanları
- Çok basit; yalnızca matris–vektör çarpımı.
- Seyrek ve dev matrislerde (milyarlarca satır) uygulanabilir.
- Bellek O(n): matris değiştirilmez.
Sınırları
- Yalnızca baskın özdeğeri bulur.
- |λ2| ≈ |λ1| ise çok yavaş; |λ1| = |λ2| ise yakınsamayabilir.
- x0, v1'e dik seçilirse (c1 = 0) kuramsal olarak başarısız olur.
- PageRank: web bağlantı matrisinin baskın özvektörü sayfaların önemini verir.
- Türevler: ters yineleme (en küçük özdeğer), kaydırmalı yineleme, Lanczos/Arnoldi; PCA'da ilk temel bileşen.
Özet
Özet
| Problem | Algoritma | Oran | Süre |
|---|---|---|---|
| TSP (genel) | en yakın komşu (sezgisel) | garanti yok | O(n²) |
| Metrik TSP | MST + önce-kök + kısayol / Christofides | 2 / 1,5 | O(n²) / O(n³) |
| TSP | 2-opt yerel arama | garanti yok | O(n²) / tarama |
| Makine çizelgeleme | liste çizelgeleme / LPT | 2 − 1/m / 4/3 − 1/(3m) | O(n log m) / O(n log n) |
| Düğüm kapsama | kenar seç, iki ucu ekle | 2 | O(V + E) |
| 0/1 sırt çantası | max(oran sıralı, en iyi tek eşya) / FPTAS | 2 / 1 + ε | O(n log n) / O(n³/ε) |
| Baskın özdeğer | Power Iteration | hata ∝ |λ₂/λ₁|k | O(n²) / adım |
Özet
Etkileşimli Simülatörler
Özet
Sık Yapılan Hatalar
Özet
Örnek Problemler
- Bir en küçükleme probleminde algoritma 30, optimum 20 buluyor. Bu girdi için oran nedir?
- 5 şehirlik matriste (TSP örneği) en yakın komşuyu 2 numaralı şehirden başlatın: tur ve uzunluk?
- 1–2–3–4–5–6 yolunda kenarlar (1,2), (2,3), …, (5,6) sırasıyla işlenirse 2-yaklaşım kaç düğüm seçer? Optimum?
- m = 2, işler 3, 3, 2, 2, 2: liste çizelgeleme ve LPT Cmax'ı ve optimum nedir?
- Benzetimli tavlamada Δ = 5 kadar kötüleştiren bir hamle T = 10 ve T = 1 iken hangi olasılıkla kabul edilir?
- W = 10, eşyalar (2, 1) ve (10, 10) (değer, ağırlık): oran sıralı açgözlü ve iyileştirilmiş kural ne bulur?
Cevapları göster
- C/C* = 30/20 = 1,5.
- 2 → 0 (15) → 1 (10) → 3 (25) → 4 (40) → 2 (35): 125.
- (1,2), (3,4), (5,6) seçilir → 6 düğüm; optimum {2, 4, 5} → 3; oran tam 2.
- Liste: 3 | 3, sonra 2 → M1 (5), 2 → M2 (5), 2 → M1 (7) → 7; LPT aynı sıra → 7; optimum {3, 3} | {2, 2, 2} = 6; 7/6 = 4/3 − 1/6 (sınır sıkı).
- e−5/10 ≈ 0,61; e−5/1 ≈ 0,0067. Sıcaklık düştükçe kötüleştiren hamleler neredeyse hiç kabul edilmez.
- Açgözlü önce (2, 1) alır, (10, 10) sığmaz → 2; iyileştirilmiş kural: max(2, 10) = 10 = optimum.
Özet
Alıştırmalar
- a(0,0), b(4,3), c(4,0), d(0,3) ve turda (a,b), (c,d) kenarları var. 2-opt kazancı Δ nedir?
- m = 3 için liste çizelgelemenin 5/3 oranına ulaştığı bir iş listesi kurun.
- K5 tam çizgesinde 2-yaklaşım kaç düğüm seçer? Optimum kaçtır?
- A = [[2, 0], [0, 1]], x0 = (1, 1). xk'nın ikinci bileşeni birincisinin 10⁻³'ünden kaç adımda küçük olur?
- Benzetimli tavlamada T₀ = 100 ve her adımda T ← 0,997 · T ise T kaç adımda 1'in altına iner?
- 2-yaklaşımı, seçilen eşleştirmeyi de döndürecek biçimde Java ile yazın.
Cevaplar / ipuçları
- d(a,c) + d(b,d) − d(a,b) − d(c,d) = 4 + 4 − 5 − 5 = −2 → hamle yapılır.
- Altı adet 1 birimlik iş, sonra bir 3 birimlik iş: liste 2 + 3 = 5; optimum {3} | {1,1,1} | {1,1,1} = 3 → 5/3.
- İki ayrık kenar seçilir → 4 düğüm; optimum n − 1 = 4 (oran 1).
- xk ∝ (2k, 1): 2−k < 10⁻³ → k = 10 (2¹⁰ = 1024).
- 100 · 0,997k < 1 → k > ln 100 / (−ln 0,997) ≈ 1532,8 → 1533 adım.
- İki ucu da işaretsiz kenarı eşleştirmeye ekleyip iki ucu işaretleyin; kapsama = eşleştirmenin uçları.
Özet
Kaynaklar
- Cormen, Leiserson, Rivest ve Stein, Introduction to Algorithms, 4. baskı, 2022 (Bölüm 35: Approximation Algorithms).
- V. V. Vazirani, Approximation Algorithms, Springer, 2001.
- D. P. Williamson ve D. B. Shmoys, The Design of Approximation Algorithms, Cambridge University Press, 2011.
- R. L. Graham, "Bounds on Multiprocessing Timing Anomalies", SIAM Journal on Applied Mathematics 17(2), 1969.
- N. Christofides, "Worst-Case Analysis of a New Heuristic for the Travelling Salesman Problem", Rapor 388, Carnegie Mellon Üniversitesi, 1976.
- M. Sipser, Introduction to the Theory of Computation, 3. baskı, 2012 (3-SAT → düğüm kapsama indirgemesi).
- G. H. Golub ve C. F. Van Loan, Matrix Computations, 4. baskı, 2013 (Power Iteration).