Bölüm 13: Geri Dönüşlü Algoritmalar
Giriş
Öğrenme Çıktıları
Geri dönüşlü aramayı (backtracking) kısmi çözüm, aday, kısıt ve budama kavramlarıyla açıklamak; durum uzayı ağacını çizmek.
"seç → keşfet → geri al" özyinelemeli şablonunu Java ile yazmak ve yeni bir probleme uyarlamak.
N vezir, Sudoku, labirent, graf boyama, Hamilton yolu ve kelime arama problemlerini adım adım çözmek.
En kötü durumun neden üstel olduğunu göstermek; budama ve sezgisellerin (MRV, en az çakışma) etkisini değerlendirmek.
Temel Fikir
Geri Dönüp Dene
- Bazen bir problemi çözmek için farklı yollar denemek ve yanlış yollardan geri dönmek gerekir.
- Geri dönüşlü arama (backtracking), karmaşık problemleri çözmek için bu stratejiyi sistemli biçimde kullanır.
- Çözüm, adım adım kısmi çözüm olarak kurulur; bir adım kısıtları bozuyorsa o dal terk edilir.
- Tüm olasılıkları körü körüne üreten kaba kuvvetten (brute force) farkı budur: geçersiz kısmi çözümlerin devamı hiç üretilmez.
Bulunan yol (turuncu) ve denenip bırakılan çıkmazlar (✗)
Temel Fikir
Labirentteki Yolcu
- Geri dönüşlü algoritma, bir labirentte yolculuk yapan kişiye benzetilebilir.
- Kişi her kavşak noktasında bir karar vererek ilerler.
- Seçtiği yol çıkışa götürmüyorsa geri dönüp başka bir yol dener.
- Her adımda bir karar verilir ve kararın doğru olup olmadığı kontrol edilir.
- Bu deneme-yanılma süreci problem çözülene (ya da tüm seçenekler tükenene) kadar sürer.
- Labirent, Sudoku ve satranç gibi bulmaca ve yapay zekâ oyunlarında kullanılır.
Temel Fikir
Labirentte Geri Dönüş Adım Adım
Giriş (G) hücresinden başlanır. Yön sırası: aşağı, sağ, yukarı, sol. Her hücre ziyaret edildiğinde işaretlenir; böylece aynı hücreye ikinci kez girilmez.
Aşağı iki adım: (2,0). Bir daha aşağısı duvar, bu yüzden bir sonraki yön (sağ) denenir.
Sağa iki adım: (2,2) bir kavşak. Önce aşağı denenecek; sağ ve yukarı duvar.
Aşağı ve sola ilerleyen koridor (4,0) hücresinde çıkmaza girer: dört yön de duvar, sınır ya da ziyaret edilmiş.
Geri dönüş: (4,0), (4,1), (4,2), (3,2) yoldan çıkarılır (✗). Kavşak (2,2) yeniden denenir ama kalan yönleri de kapalı.
Geri dönüş girişe kadar sürer: (2,2), (2,1), (2,0), (1,0) de çıkmaz. Girişte sıradaki yön sağ denenir.
Üst koridor boyunca sağa: (0,4). Aşağısı açık.
(1,4), (2,4), (3,4) üzerinden çıkışa (Ç) ulaşıldı. Yol 9 hücre; 8 hücre çıkmaz sokak olarak denendi ve bırakıldı.
Temel Fikir
Durum Uzayı Ağacı (State-Space Tree)
Temel Fikir
Genel Şablon: Seç → Keşfet → Geri Al
void geriDon(Durum kismi) { if (cozumMu(kismi)) { kaydet(kismi); return; } for (Aday a : adaylar(kismi)) { if (gecerliMi(kismi, a)) { ekle(kismi, a); // seç geriDon(kismi); // keşfet cikar(kismi, a); // geri al } } }
- Hedef testi: kısmi çözüm tamamsa kaydet (ya da dur).
- Seç: sıradaki adayı kısmi çözüme ekle.
- Keşfet: özyinelemeyle bir seviye derine in.
- Geri al: adayı çıkar; durum çağrıdan önceki hâline döner, sıradaki aday denenir.
gecerliMi içinde olur: geçersiz aday için özyinelemeli çağrı hiç yapılmaz, böylece o adayın altındaki tüm alt ağaç atlanır. Tek çözüm yetiyorsa geriDon boolean döndürür ve ilk true'da durulur.Temel Fikir
Kaba Kuvvet ve Budama: 8 Vezir
| Yaklaşım | İncelenen aday | Açıklama |
|---|---|---|
| 64 kareden 8'ini seç | 4 426 165 368 | C(64, 8): her yerleşimi üret, sonra test et |
| Her satıra bir vezir | 16 777 216 | 8⁸ tam yerleşim |
| Her satıra bir vezir, sütunlar farklı | 40 320 | 8! permütasyon |
| Geri dönüşlü, tüm çözümler | 2056 | güvenli yerleştirme sayısı (92 çözüm) |
| Geri dönüşlü, ilk çözüm | 113 | güvenli yerleştirme; 105 geri alma |
Temel Fikir
Avantajlar ve Dezavantajlar
Avantajlar
- Çok çeşitli problemlere uygulanabilen genel bir yöntemdir.
- Çözümleri ağaç olarak ifade edilebilen problemlerde çoğu zaman verimlidir.
- Anlaması ve uygulaması kolaydır: kısa, özyinelemeli kod.
- Tüm çözümleri ya da hiç çözüm olmadığını kesin olarak bulur (tam arama).
Dezavantajlar
- En kötü durumda zaman karmaşıklığı üsteldir (2ⁿ, n!, 9ᵐ …).
- Olası çözüm sayısı çok büyük olduğunda yavaşlar; iyi budama ve sezgisel gerekir.
- Derin özyineleme yığın belleği kullanır: O(derinlik).
- Aynı alt problem farklı yollardan tekrar tekrar çözülebilir (DP'deki gibi saklanmaz).
N Vezir Problemi
8 Vezir Problemi (Eight Queens)
- Bir 8×8 satranç tahtasına 8 vezirin yerleştirilmesi.
- Amaç: hiçbir vezirin diğerini tehdit etmediği bir yerleşim bulmak. Vezir aynı satır, sütun ve çaprazdaki taşları tehdit eder.
- Genelleştirilmiş hâli: n×n tahtaya n vezir (N-Queens). n = 2 ve n = 3 dışında her n ≥ 1 için çözüm vardır.
- 8 vezirin 92 çözümü vardır (simetriler ayıklanınca 12 temel çözüm).
- Geri dönüşlü algoritma bu tür problemleri çözmek için kullanılır.
Bir çözüm: a1, b7, c4, d6, e8, f2, g5, h3
N Vezir Problemi
Geri Dönüşlü Çözüm: Adımlar
- Tahtanın her hücresi başlangıçta boş.
- İlk vezir ilk satırda bir sütuna yerleştirilir.
- Yerleştirilen vezirin önceki vezirlerle çakışıp çakışmadığı kontrol edilir (sütun ve iki çapraz).
- Çakışma yoksa konum geçerli kabul edilir; bir sonraki vezir bir sonraki satıra yerleştirilir.
- Bir satırda tüm sütunlar denenip güvenli yer bulunamazsa, bir önceki vezir yer değiştirilir (geri dönüş).
- Tüm 8 vezir yerleştirildiğinde çözüm bulunmuş olur.
N Vezir Problemi
4 Vezir: Tahta ve Durum Uzayı Ağacı
Boş tahta. Vezirler satır satır yerleştirilir; her satırda sütun 0, 1, 2, 3 sırayla denenir. Ağaçtaki düğüm, o satırda seçilen sütunu gösterir.
Satır 0: sütun 0 güvenli → vezir yerleştirilir, bir alt seviyeye (satır 1) inilir.
Satır 1: sütun 0, 1 tehdit altında; sütun 2 güvenli → vezir yerleştirilir, bir alt seviyeye (satır 2) inilir.
Satır 2: sütun 0, 1, 2, 3 tehdit altında → güvenli sütun yok (çıkmaz). Geri dön: satır 1'deki vezir (sütun 2) kaldırılır ve o satırda sıradaki sütun denenir.
Satır 1: sütun 3 güvenli → vezir yerleştirilir, bir alt seviyeye (satır 2) inilir.
Satır 2: sütun 0 tehdit altında; sütun 1 güvenli → vezir yerleştirilir, bir alt seviyeye (satır 3) inilir.
Satır 3: sütun 0, 1, 2, 3 tehdit altında → güvenli sütun yok (çıkmaz). Geri dön: satır 2'deki vezir (sütun 1) kaldırılır ve o satırda sıradaki sütun denenir.
Satır 2: sütun 2, 3 tehdit altında → güvenli sütun yok (çıkmaz). Geri dön: satır 1'deki vezir (sütun 3) kaldırılır ve o satırda sıradaki sütun denenir.
Satır 1'in denenecek başka sütunu kalmadı. Geri dön: satır 0'daki vezir (sütun 0) da kaldırılır.
Satır 0: sütun 1 güvenli → vezir yerleştirilir, bir alt seviyeye (satır 1) inilir.
Satır 1: sütun 0, 1, 2 tehdit altında; sütun 3 güvenli → vezir yerleştirilir, bir alt seviyeye (satır 2) inilir.
Satır 2: sütun 0 güvenli → vezir yerleştirilir, bir alt seviyeye (satır 3) inilir.
Satır 3: sütun 0, 1 tehdit altında; sütun 2 güvenli → dördüncü vezir yerleşti. satir == n: çözüm bulundu: sütunlar [1, 3, 0, 2]. Toplam 8 yerleştirme, 4 geri dönüş.
Kırmızı hücre: mevcut vezirlerce tehdit edilen kare · turuncu düğüm: son yerleştirilen · kesikli ✗: geri dönülen dal · yeşil: çözüm.
N Vezir Problemi
N Vezir: Java Kodu
boolean guvenliMi(int[][] t, int s, int k) { // aynı sütun for (int i = 0; i < s; i++) if (t[i][k] == 1) return false; // sol üst çapraz for (int i = s-1, j = k-1; i >= 0 && j >= 0; i--, j--) if (t[i][j] == 1) return false; // sağ üst çapraz for (int i = s-1, j = k+1; i >= 0 && j < n; i--, j++) if (t[i][j] == 1) return false; return true; }
boolean coz(int[][] t, int satir) { if (satir == n) return true; for (int sutun = 0; sutun < n; sutun++) { if (guvenliMi(t, satir, sutun)) { t[satir][sutun] = 1; // yerleştir if (coz(t, satir + 1)) return true; t[satir][sutun] = 0; // geri al } } return false; }
t[i][j] == 1: (i, j)'de vezir var;nsınıfın bir alanı. Vezirler yalnızca üst satırlarda olduğundanguvenliMiüç yöne bakar: yukarı, sol üst ve sağ üst çapraz.cozsatır satır ilerler; ilk çözümdetruedöner ve yığın boyunca yukarı taşınır.guvenliMiO(n);cozen kötü durumda O(n!).
N Vezir Problemi · Kodu adım adım çalıştır
coz(t, 0), n = 4: Kodu Adım Adım İzle
coz(t, 0) çağrıldı: tahta boş, satir = 0.
(0, 0) güvenli → t[0][0] = 1, ardından coz(t, 1) çağrılır.
(1, 0) tehdit altında (aynı sütun: (0, 0)) → guvenliMi false, sonraki sütun.
(1, 1) tehdit altında (çapraz: (0, 0)) → guvenliMi false, sonraki sütun.
(1, 2) güvenli → t[1][2] = 1, ardından coz(t, 2) çağrılır.
(2, 0) tehdit altında (aynı sütun: (0, 0)) → guvenliMi false, sonraki sütun.
(2, 1) tehdit altında (çapraz: (1, 2)) → guvenliMi false, sonraki sütun.
(2, 2) tehdit altında (çapraz: (0, 0)) → guvenliMi false, sonraki sütun.
(2, 3) tehdit altında (çapraz: (1, 2)) → guvenliMi false, sonraki sütun.
Satır 2 için döngü bitti, güvenli sütun yok → return false.
coz(t, 2) false döndü → geri al: t[1][2] = 0; döngü sütun 3 ile sürer.
(1, 3) güvenli → t[1][3] = 1, ardından coz(t, 2) çağrılır.
(2, 0) tehdit altında (aynı sütun: (0, 0)) → guvenliMi false, sonraki sütun.
(2, 1) güvenli → t[2][1] = 1, ardından coz(t, 3) çağrılır.
(3, 0) tehdit altında (aynı sütun: (0, 0)) → guvenliMi false, sonraki sütun.
(3, 1) tehdit altında (çapraz: (1, 3)) → guvenliMi false, sonraki sütun.
(3, 2) tehdit altında (çapraz: (2, 1)) → guvenliMi false, sonraki sütun.
(3, 3) tehdit altında (çapraz: (0, 0)) → guvenliMi false, sonraki sütun.
Satır 3 için döngü bitti, güvenli sütun yok → return false.
coz(t, 3) false döndü → geri al: t[2][1] = 0; döngü sütun 2 ile sürer.
(2, 2) tehdit altında (çapraz: (0, 0)) → guvenliMi false, sonraki sütun.
(2, 3) tehdit altında (aynı sütun: (1, 3)) → guvenliMi false, sonraki sütun.
Satır 2 için döngü bitti, güvenli sütun yok → return false.
coz(t, 2) false döndü → geri al: t[1][3] = 0; döngü sütun 4 ile sürer.
Satır 1 için döngü bitti, güvenli sütun yok → return false.
coz(t, 1) false döndü → geri al: t[0][0] = 0; döngü sütun 1 ile sürer.
(0, 1) güvenli → t[0][1] = 1, ardından coz(t, 1) çağrılır.
(1, 0) tehdit altında (çapraz: (0, 1)) → guvenliMi false, sonraki sütun.
(1, 1) tehdit altında (aynı sütun: (0, 1)) → guvenliMi false, sonraki sütun.
(1, 2) tehdit altında (çapraz: (0, 1)) → guvenliMi false, sonraki sütun.
(1, 3) güvenli → t[1][3] = 1, ardından coz(t, 2) çağrılır.
(2, 0) güvenli → t[2][0] = 1, ardından coz(t, 3) çağrılır.
(3, 0) tehdit altında (aynı sütun: (2, 0)) → guvenliMi false, sonraki sütun.
(3, 1) tehdit altında (aynı sütun: (0, 1)) → guvenliMi false, sonraki sütun.
(3, 2) güvenli → t[3][2] = 1, ardından coz(t, 4) çağrılır.
satir == n → true. true değeri yığın boyunca yukarı taşınır: çözüm [1, 3, 0, 2].
boolean coz(int[][] t, int satir) { if (satir == n) return true; for (int sutun = 0; sutun < n; sutun++) { if (guvenliMi(t, satir, sutun)) { t[satir][sutun] = 1; if (coz(t, satir + 1)) return true; t[satir][sutun] = 0; // geri al } } return false; }
N Vezir Problemi
8 Vezir: Algoritmanın İlk Çözümü
Satır 0–7 için sütunlar: [0, 4, 7, 5, 2, 6, 1, 3]
coz(t, 0)(n = 8) sütunları küçükten büyüğe denediği için her zaman sözlük sırasında ilk çözümü bulur.- Bu çözüme ulaşana kadar 876 kez
guvenliMiçağrılır, 113 vezir yerleştirilir ve 105 kez geri dönülür. - Önceki slayttaki yerleşim (a1, b7, c4, d6, e8, f2, g5, h3) başka bir çözümdür; 92 çözümün hepsi geçerlidir.
- Tüm çözümleri bulmak için
satir == nolduğunda çözümü kaydedipfalsedöndürmek (aramayı sürdürmek) yeterlidir.
N Vezir Problemi
N Vezir: Çözüm ve Yerleştirme Sayıları
| n | Çözüm | nⁿ (kaba) | Yerleştirme (tümü) | İlk çözüme kadar |
|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 1 |
| 2 | 0 | 4 | 2 | — |
| 3 | 0 | 27 | 5 | — |
| 4 | 2 | 256 | 16 | 8 |
| 5 | 10 | 3 125 | 53 | 5 |
| 6 | 4 | 46 656 | 152 | 31 |
| 7 | 40 | 823 543 | 551 | 9 |
| 8 | 92 | 16 777 216 | 2056 | 113 |
| 9 | 352 | 387 420 489 | 8393 | 41 |
| 10 | 724 | 10 000 000 000 | 35538 | 102 |
- n = 2 ve 3 için çözüm yoktur: algoritma tüm ağacı gezip
falsedöner. - "Yerleştirme": güvenli bulunup tahtaya konan vezir sayısı (ağaçtaki kök dışı düğüm).
- Tüm çözümleri bulma maliyeti nⁿ'den çok küçük, ama yine de hızla (yaklaşık n! gibi) büyür.
- İlk çözüme kadar geçen iş n ile düzgün artmaz: n = 6'da 31, n = 7'de yalnız 9 yerleştirme.
N Vezir Problemi
Daha Hızlı Güvenlik Testi: O(1)
boolean[] sut = new boolean[n]; boolean[] k1 = new boolean[2*n-1]; // r+c boolean[] k2 = new boolean[2*n-1]; // r-c+n-1 void coz(int r) { if (r == n) { sayac++; return; } for (int c = 0; c < n; c++) { int a = r + c, b = r - c + n - 1; if (sut[c] || k1[a] || k2[b]) continue; sut[c] = k1[a] = k2[b] = true; coz(r + 1); sut[c] = k1[a] = k2[b] = false; } }
- Aynı ters köşegendeki hücrelerde r + c sabittir (0 … 2n − 2).
- Aynı köşegendeki hücrelerde r − c sabittir; + n − 1 ile indis 0'dan başlar.
guvenliMi O(n) yerine O(1) olur; tahta dizisine bile gerek kalmaz (yalnızca yer[satir] = sutun).N Vezir Problemi
Deneyin: N Vezir Geri Dönüşlü Arama
Kırmızı kare: tehdit altında · yeşil çerçeve: güvenli deneme · kırmızı çerçeve: reddedilen deneme · yeşil vezirler: çözüm.
En Az Çakışma
En Az Çakışma Sezgiseli (Min-Conflicts)
- Farklı bir fikir: önce tüm vezirler yerleştirilir (her sütuna bir tane), sonra çakışmalar yerel değişikliklerle onarılır.
- Her hücreye yazılan sayı: o satıra konacak vezirin kaç vezirle çakışacağı (satır + çaprazlar).
- Başlangıç: sütun sütun, en az çakışmalı satırı seç (eşitlikte rastgele).
- Onarım: çakışan bir vezir seç; sütunu içinde en az çakışmalı satıra taşı. Çakışma kalmayınca dur.
- Bu bir yerel arama (local search) yöntemidir: geri dönüş yığını yoktur, tam değildir, ama büyük n'de son derece hızlıdır.
enAzCakisma(n, maksAdim): // başlangıç: açgözlü yerleşim for k = 0 .. n-1: yer[k] = en az çakışmalı satır for adim = 1 .. maksAdim: if çakışma yok: return yer k = rastgele çakışan sütun yer[k] = argmin_r cakisma(k, r) // eşitlikte rastgele return başarısız
En Az Çakışma
En Az Çakışma: Başlangıç Yerleşimi
Sütun 0: henüz vezir yok, her satırın çakışma sayısı 0. Eşitlikte rastgele seçilir → satır 7.
Sütun 1 için her satırın çakışma sayısı yazıldı (önceki vezirlerle aynı satır/çapraz). En küçük değer 0 (satır 0, 1, 2, 3, 4, 5) → seçilen: satır 2.
Sütun 2 için her satırın çakışma sayısı yazıldı (önceki vezirlerle aynı satır/çapraz). En küçük değer 0 (satır 0, 4, 6) → seçilen: satır 4.
Sütun 3 için her satırın çakışma sayısı yazıldı (önceki vezirlerle aynı satır/çapraz). En küçük değer 0 (satır 1, 6) → seçilen: satır 1.
Sütun 4 için her satırın çakışma sayısı yazıldı (önceki vezirlerle aynı satır/çapraz). En küçük değer 1 (satır 0, 1, 3, 4, 5, 6, 7) → seçilen: satır 4. Hiçbir satır çakışmasız değil; çakışmaya izin verilir (kırmızı çizgi).
Sütun 5 için her satırın çakışma sayısı yazıldı (önceki vezirlerle aynı satır/çapraz). En küçük değer 0 (satır 0) → seçilen: satır 0.
Sütun 6 için her satırın çakışma sayısı yazıldı (önceki vezirlerle aynı satır/çapraz). En küçük değer 0 (satır 3, 5) → seçilen: satır 3.
Sütun 7 için her satırın çakışma sayısı yazıldı (önceki vezirlerle aynı satır/çapraz). En küçük değer 0 (satır 6) → seçilen: satır 6.
Sekiz vezir yerleşti: [7, 2, 4, 1, 4, 0, 3, 6] (sütun sırasıyla satırlar). Yalnızca bir çift çakışıyor: (4, 2) ile (4, 4) aynı satırda. Şimdi onarım başlar.
Vurgulu sütun: karar verilen sütun · yeşil sayı: en az çakışma · kırmızı çizgi: çakışan çift.
En Az Çakışma
En Az Çakışma: Onarım Adımları
Çakışan vezirlerden biri seçilir: sütun 4 (şu an 1 çakışma). Diğer satırların en küçüğü 1 (satır 7) → vezir satır 7'ye taşınır.
Taşıma yeni bir çakışma doğurdu: sütun 0 ile sütun 4 artık aynı satırda (7). Sütun 0'ın seçenekleri: en küçük 1 (satır 0, 5). Toplam çakışan çift: 1.
Birkaç onarım adımı sonra: sütun 5'teki vezir satır 3'te, sütun 2 ile çakışıyor. En küçük değer 1 (satır 4, 5) → satır 4.
Satır 4'te bu kez (6, 7) ile çapraz çakışma var (1). Satır 3, 4, 5'in hepsi 1 çakışmalı: bir plato. Rastgele seçimle satır 5'e geçer.
Satır 5'te sütun 1 ile aynı satırda. Sütun 5 platoda 3 ↔ 4 ↔ 5 arasında birkaç kez gidip gelir; rastgele seçim sayesinde sonunda başka bir vezir seçilir.
Sütun 1 seçildi (satır 5, 1 çakışma). En küçük değer 1 (satır 7) → satır 7.
Şimdi sütun 1 ile sütun 4 satır 7'de çakışıyor. Sütun 4'ün en küçüğü 1 (satır 0, 2) → satır 2.
Sütun 0 ile sütun 4 satır 2'de çakışıyor. Sütun 0'da satır 4 0 çakışmalı → vezir oraya taşınır.
Çakışan vezir kalmadı: çözüm [4, 7, 3, 0, 2, 5, 1, 6]. Algoritma 8 vezirin hepsini baştan yerleştirdi, sonra yalnızca yerel değişikliklerle çakışmaları giderdi.
Vurgulu sütundaki sayılar, kırmızı vezirin o satıra taşınması hâlinde kaç vezirle çakışacağını gösterir (vezirin kendi satırı boş bırakıldı).
En Az Çakışma
Geri Dönüşlü Arama ve En Az Çakışma
| Geri dönüşlü arama | En az çakışma | |
|---|---|---|
| Durum | Kısmi ama hep geçerli yerleşim | Tam ama geçersiz olabilen yerleşim |
| Hamle | Bir vezir ekle / geri al | Bir veziri sütunu içinde taşı |
| Tamlık | Tam: çözüm varsa bulur, yoksa kanıtlar | Tam değil: platoda dolaşabilir, adım sınırı gerekir |
| Tüm çözümler | Hepsini sayabilir (92) | Yalnızca bir çözüm |
| Büyük n | n büyüdükçe hızla yavaşlar | n = 1 000 000 için bile ortalama birkaç onlu adımda çözer |
| Bellek | O(n) yığın | O(n) dizi |
Sudoku
Sudoku
- Sudoku'nun amacı, 9×9'luk bir karede her satır, her sütun ve her 3×3'lük küçük karede 1'den 9'a kadar olan rakamları birer kez kullanmaktır.
- Bazı hücreler baştan verilir (ipucu); geri kalanlar doldurulur.
- Bu bir kısıt sağlama problemidir (constraint satisfaction): değişkenler boş hücreler, alan {1, …, 9}, kısıtlar "aynı birimde farklı".
Sudoku
Sudoku: Geri Dönüşlü Algoritma
- Boş bir hücreye bir rakam ata.
- Atanan rakam geçerliyse (satır, sütun ve kutuda yoksa) bir sonraki boş hücreye devam et.
- Geçerli değilse sıradaki rakamı dene.
- Bir hücrede tüm rakamlar denenmişse: önceki hücreye geri dön (backtrack) ve orada farklı bir rakam dene.
- Tüm hücreler dolana kadar adımları tekrarla.
gecerliMi, hedef = boş hücre kalmaması.Sudoku
Sudoku: Java Kodu
boolean coz(int[][] t) { for (int s = 0; s < 9; s++) for (int k = 0; k < 9; k++) if (t[s][k] == 0) { for (int r = 1; r <= 9; r++) if (gecerliMi(t, s, k, r)) { t[s][k] = r; if (coz(t)) return true; t[s][k] = 0; // geri al } return false; // rakam yok } return true; // boş hücre yok }
boolean gecerliMi(int[][] t, int s, int k, int r) { for (int i = 0; i < 9; i++) if (t[s][i] == r || t[i][k] == r) return false; int bs = s / 3 * 3; int bk = k / 3 * 3; for (int i = bs; i < bs + 3; i++) for (int j = bk; j < bk + 3; j++) if (t[i][j] == r) return false; return true; }
coz her çağrıda ilk boş hücreyi baştan arar (O(81)); bir hücrede hiçbir rakam olmazsa return false geri dönüşü tetikler.
Sudoku
Sudoku: Geri Dönüşlü Çözüm Adım Adım
Bulmaca: 30 ipucu, 51 boş hücre. Boş hücreler satır satır, soldan sağa doldurulur; her hücrede 1–9 sırayla denenir.
İlk beş boş hücreye 1, 2, 4, 8, 9 girildi. (0, 8) için hiçbir rakam geçerli değil: satırda yalnız 6 eksik, o da sütunda var → çıkmaz. (şu ana kadar 5 yerleştirme, 0 geri alma)
Geri dönüş: (0, 7)'deki 9 silinir, (0, 6) 9 ile denenir, yine çıkmaz; geri dönüş (0, 5)'e kadar sürer ve orada 4 yerine 6 denenir. (şu ana kadar 7 yerleştirme, 4 geri alma)
Satır 0 ilk kez tamamlandı: 5 3 1 2 7 6 4 9 8. Bu satır kendi içinde geçerli, ama çözüme götürüp götürmediği henüz bilinmiyor. (şu ana kadar 10 yerleştirme, 4 geri alma)
Satır 1'deki tüm denemeler çıkmaza girdi. Geri dönüş satır 0'a kadar uzanır: (0, 8)'deki 8 silinir. Erken verilen bir karar ancak çok sonra yanlış çıkabilir. (şu ana kadar 31 yerleştirme, 26 geri alma)
Satır 1 ilk kez tamamlandı. (şu ana kadar 229 yerleştirme, 218 geri alma)
Satır 2 ilk kez tamamlandı; ilk üç satır son çözümdekiyle aynı. (şu ana kadar 377 yerleştirme, 360 geri alma)
Satır 3 ilk kez tamamlandı. (şu ana kadar 395 yerleştirme, 372 geri alma)
Satır 4 ilk kez tamamlandı. (şu ana kadar 1520 yerleştirme, 1492 geri alma)
Satır 5 ilk kez tamamlandı. (şu ana kadar 4185 yerleştirme, 4151 geri alma)
Satır 6 ilk kez tamamlandı. (şu ana kadar 4197 yerleştirme, 4157 geri alma)
Satır 7 ilk kez tamamlandı. (şu ana kadar 4202 yerleştirme, 4157 geri alma)
Çözüm bulundu: 51 boş hücrenin hepsi dolu, tüm kısıtlar sağlanıyor. Toplam 4208 yerleştirme ve 4157 geri alma.
Siyah: ipucu · mavi: algoritmanın yazdığı rakam · turuncu: son yazılan hücre · kırmızı ✗: rakam kalmayan (çıkmaz) hücre.
Sudoku
Sudoku: Çözüm ve Maliyet
| Strateji | Yerleştirme | Geri alma |
|---|---|---|
| Satır satır, ilk boş hücre | 4208 | 4157 |
| MRV: en az adaylı hücre | 51 | 0 |
- Kaba kuvvet: 51 boş hücre için 9⁵¹ ≈ 4,6 · 10⁴⁸ atama. Budama bunu birkaç bine indirir.
- MRV (minimum remaining values): her adımda en az adayı kalan hücreyi doldur. Bu bulmacada her seferinde tek adaylı hücre bulunur: hiç geri dönüş gerekmez.
Diğer Problemler
Graf Boyama (m-Coloring)
Komşu iki düğüm aynı rengi almayacak biçimde düğümlere en fazla m renk ata. Kısmi çözüm: ilk k düğümün renkleri; kısıt: komşuyla aynı renk olmamak.
Altı düğümlü graf, m = 3 renk (1 mavi, 2 yeşil, 3 turuncu). Düğümler 0, 1, 2, … sırasıyla boyanır; her düğümde renk 1, 2, 3 sırayla denenir.
Düğüm 0: renk 1 (mavi) uygun → atanır.
Düğüm 1: renk 1 komşuda var; renk 2 (yeşil) uygun → atanır.
Düğüm 2: renk 1 komşuda var; renk 2 (yeşil) uygun → atanır.
Düğüm 3: renk 1 (mavi) uygun → atanır.
Düğüm 4: renk 1, 2 komşuda var; renk 3 (turuncu) uygun → atanır.
Düğüm 5: renk 1, 2, 3 komşularda kullanılıyor → hiçbir renk uygun değil (çıkmaz). Geri dön: düğüm 4'ün rengi (3) silinir, sıradaki renk denenecek.
Düğüm 4: denenecek başka renk kalmadı (çıkmaz). Geri dön: düğüm 3'ün rengi (1) silinir, sıradaki renk denenecek.
Düğüm 3: renk 2 komşuda var; renk 3 (turuncu) uygun → atanır.
Düğüm 4: renk 1 (mavi) uygun → atanır.
Düğüm 5: renk 1, 2 komşuda var; renk 3 (turuncu) uygun → atanır. Altı düğüm de boyandı: geçerli 3-boyama bulundu.
Diğer Problemler
Hamilton Yolu (Hamiltonian Path)
Grafın her düğümünü tam bir kez ziyaret eden yol. Kısmi çözüm: yol[0..konum−1]; kısıt: yeni düğüm son düğüme komşu ve yolda yok.
yol[0] = 0; konum = 1. Her konumda düğümler 0, 1, 2, … sırasıyla denenir: önceki düğüme komşu ve yolda olmayan düğüm eklenebilir.
Konum 1: düğüm 1 uygun → yol[1] = 1.
Konum 2: düğüm 3 uygun → yol[2] = 3.
Konum 3: düğüm 2 uygun → yol[3] = 2.
Konum 4: son düğüm 2'nin yolda olmayan (denenmemiş) komşusu kalmadı → çıkmaz. Geri dön: yol[3] = −1 (düğüm 2 çıkarılır).
Konum 3: düğüm 4 uygun → yol[3] = 4.
Konum 4: son düğüm 4'ün yolda olmayan (denenmemiş) komşusu kalmadı → çıkmaz. Geri dön: yol[3] = −1 (düğüm 4 çıkarılır).
Konum 3: son düğüm 3'ün yolda olmayan (denenmemiş) komşusu kalmadı → çıkmaz. Geri dön: yol[2] = −1 (düğüm 3 çıkarılır).
Konum 2: düğüm 4 uygun → yol[2] = 4.
Konum 3: düğüm 3 uygun → yol[3] = 3.
Konum 4: düğüm 2 uygun → yol[4] = 2. konum == 5: tüm düğümler yolda, Hamilton yolu bulundu: 0 → 1 → 4 → 3 → 2.
Diğer Problemler
Hamilton Yolu: Java Kodu
boolean bul(int[][] graf, int[] yol, int konum) { if (konum == graf.length) return true; for (int v = 0; v < graf.length; v++) { if (uygunMu(v, graf, yol, konum)) { yol[konum] = v; if (bul(graf, yol, konum + 1)) return true; yol[konum] = -1; // geri al } } return false; } boolean uygunMu(int v, int[][] graf, int[] yol, int konum) { if (graf[yol[konum - 1]][v] == 0) return false; for (int i = 0; i < konum; i++) if (yol[i] == v) return false; return true; }
graf: komşuluk matrisi;yol[0] = 0ile başlanır,bul(graf, yol, 1)çağrılır.- Örnekteki 0 → 1 → 4 → 3 → 2 yolunda son düğüm 2 ile başlangıç 0 da komşudur; böyle bir yol aynı zamanda bir Hamilton döngüsüdür.
- En kötü durum O(n!) yol;
uygunMuO(n) → O(n · n!).
Diğer Problemler
Kelime Arama (Word Search)
Harf ızgarasında, komşu (yukarı/aşağı/sol/sağ) hücrelerden geçerek kelimeyi oluşturan bir yol var mı? Her hücre bir yolda en fazla bir kez kullanılır.
Aranan kelime "SEE". Her hücre başlangıç olarak denenir (satır satır); komşu yönler: yukarı, aşağı, sol, sağ. Bir hücre aynı yolda iki kez kullanılamaz.
(1, 0) = 'S' kelimenin 0. harfiyle eşleşti → ziyaret edildi olarak işaretlenir.
(1, 0) hücresinden hiçbir komşu 'E' ile devam etmiyor → geri dön, işaret kaldırılır.
(1, 3) = 'S' kelimenin 0. harfiyle eşleşti → ziyaret edildi olarak işaretlenir.
(0, 3) = 'E' kelimenin 1. harfiyle eşleşti → ziyaret edildi olarak işaretlenir.
(0, 3) hücresinden hiçbir komşu 'E' ile devam etmiyor → geri dön, işaret kaldırılır.
(2, 3) = 'E' kelimenin 1. harfiyle eşleşti → ziyaret edildi olarak işaretlenir.
(2, 2) = 'E' kelimenin 2. harfiyle eşleşti → ziyaret edildi olarak işaretlenir. Son harf de eşleşti: "SEE" bulundu.
Diğer Problemler
Kelime Arama: Java Kodu
boolean ara(char[][] iz, String kelime, int i, int s, int k, boolean[][] ziyaret) { if (i == kelime.length()) return true; if (s < 0 || s >= iz.length || k < 0 || k >= iz[0].length || ziyaret[s][k] || iz[s][k] != kelime.charAt(i)) return false; ziyaret[s][k] = true; for (int d = 0; d < 4; d++) if (ara(iz, kelime, i + 1, s + ds[d], k + dk[d], ziyaret)) return true; ziyaret[s][k] = false; // geri al return false; }
| Kelime | Sonuç |
|---|---|
| ABCCED | var |
| SEE | var |
| ABCB | yok: B iki kez kullanılamaz |
| SADE | var |
Izgara: ABCE / SFCS / ADEE. Geri dönüşte ziyaret işareti kaldırılmalıdır; yoksa hücre başka bir yolda kullanılamaz.
Diğer Problemler
Geri Dönüşle Çözülen Diğer Problemler
| Problem | Her seviyedeki seçim | Budama (kısıt) |
|---|---|---|
| Alt küme toplamı / sırt çantası | i. eleman alınsın mı? (2 dal) | toplam / ağırlık sınırı aşıldı |
| Gezgin satıcı (TSP) | sıradaki şehir | yol, bilinen en iyi turdan uzun |
| Kutu yerleştirme (bin packing) | eşya hangi kutuya? | kutu kapasitesi aşıldı |
| Maksimum kapsama | küme seçilsin mi? | kalan kümelerle iyileşme mümkün değil |
| Mantıksal doyurulabilirlik (SAT) | değişken = doğru / yanlış | bir cümle (clause) yanlış oldu |
| Mayın tarlası | hücre mayın mı? | açılmış sayılarla çelişki |
| Permütasyon / kombinasyon üretimi | sıradaki eleman | eleman zaten kullanıldı |
Eniyileme problemlerinde (TSP, sırt çantası) "bilinen en iyiden kötü" dalı kesmek dal ve sınır (branch and bound) yönteminin temelidir: Bölüm 14.
Analiz
Karmaşıklık
| Problem | En kötü zaman | Açıklama |
|---|---|---|
| N vezir | O(n!) | satır başına bir vezir, sütunlar farklı; dizili test ile O(n · n!) |
| Sudoku | O(9ᵐ) | m: boş hücre sayısı; her hücrede 9 aday |
| Graf m-boyama | O(n · mⁿ) | n düğüm, her biri m renk; denetim O(derece) |
| Hamilton yolu | O(n · n!) | yoldaki her konum için kalan düğümler |
| Kelime arama | O(R · C · 3ᴸ) | ilk harften sonra en fazla 3 yeni yön (geri gelinen hücre ziyaretli) |
| Alt kümeler / permütasyonlar | O(2ⁿ) / O(n · n!) | ağaçtaki yaprak sayısı |
Analiz
Budamayı Güçlendirme: Sezgiseller
Analiz
Paradigmaların Karşılaştırması
| Paradigma | Fikir | Ne zaman? |
|---|---|---|
| Kaba kuvvet | Tüm adayları üret, sonra test et | Uzay çok küçükse |
| Açgözlü (Bölüm 12) | Her adımda yerel en iyi; geri dönmez | Açgözlü seçim özelliği kanıtlanmışsa |
| Dinamik programlama | Örtüşen alt problemleri bir kez çöz, sakla | Alt problem sayısı polinom ise |
| Geri dönüşlü | Kısmi çözümü genişlet, geçersizse geri al | Kısıt sağlama; tüm çözümler; karar problemleri |
| Dal ve sınır (Bölüm 14) | Geri dönüş + en iyi çözüme göre sınır ile budama | Eniyileme (TSP, sırt çantası) |
Özet
Özet
| Konu | Hatırlanacaklar |
|---|---|
| Fikir | kısmi çözümü adım adım kur; kısıt bozulursa son kararı geri al, sıradakini dene |
| Şablon | hedef testi → her aday için: geçerliyse seç, özyinele, geri al |
| Durum uzayı | DFS ile gezilen ağaç; budama geçersiz alt ağaçları atlar |
| N vezir | satır satır; sütun + 2 çapraz denetimi; 8 için 92 çözüm, ilk: [0, 4, 7, 5, 2, 6, 1, 3] |
| En az çakışma | tam yerleşim + yerel onarım; hızlı ama tam değil |
| Sudoku | boş hücreye 1–9; satır/sütun/kutu denetimi; MRV ile çok daha hızlı |
| Diğerleri | graf boyama, Hamilton yolu, kelime arama (ziyaret işaretini geri al!) |
| Maliyet | en kötü üstel (2ⁿ, n!, 9ᵐ); bellek O(derinlik) |
Özet
Sık Yapılan Hatalar
t[s][k] = 0, ziyaret = false yapılmazsa eski seçim sonraki dalları bozar.if (coz(...)) return true; yerine yalnızca coz(...) yazmak: çözüm bulunsa da arama sürer ve tahta geri alınır.return falseİlk geçersiz adayda döngüden çıkmak; sıradaki adaylar hiç denenmez.sonuclar.add(yol) yerine kopya (new ArrayList<>(yol)) eklenmeli.Özet
Örnek Problemler
- 4 vezir:
coz(t, 0)ilk çözümü bulana kadar kaç vezir yerleştirir, kaç kez geri döner? - 5 vezir için algoritmanın ilk çözümü nedir? Kaç kez geri dönülür?
- {3, 5, 6, 7} içinde toplamı 15 olan alt küme (önce "al" dalı; toplam aşılınca budama). İlk bulunan?
- 5 düğümlü döngü grafı (C₅) 2 renkle boyanabilir mi? En az kaç renk gerekir?
- ABCE / SFCS / ADEE ızgarasında "ABCB" neden bulunamaz, "SADE" hangi yolla bulunur?
- 8 vezir: 8⁸ tam yerleşimi test etmek ile geri dönüşlü aramayı (tüm çözümler) karşılaştırın.
Cevapları göster
- 8 yerleştirme, 4 geri dönüş; çözüm [1, 3, 0, 2].
- [0, 2, 4, 1, 3]; hiç geri dönülmez (5 yerleştirme).
- 3, 5, 6 (14) → +7 = 21 > 15 budanır; 6 çıkarılır → 3, 5, 7 = 15: {3, 5, 7}.
- Hayır: tek uzunluklu döngü 2 renkle boyanamaz (5. düğüm hem 1. hem 4. düğümle komşu). 3 renk gerekir.
- ABCB: A→B→C'den sonra komşu B, zaten kullanılan (0, 1) hücresi. SADE: (1, 0) S → (2, 0) A → (2, 1) D → (2, 2) E.
- 8⁸ = 16 777 216 tam yerleşim; geri dönüşlü arama 2056 güvenli yerleştirme yapar (~8 000 kat az).
Özet
Alıştırmalar
- N vezir kodunu tüm çözümleri sayacak biçimde değiştirin (n = 8).
- {1, 2, 3}'ün permütasyonlarını geri dönüşle üretin. Ağaçta kök dahil kaç düğüm vardır?
- Hamilton yolu kodunu Hamilton döngüsü arayacak biçimde değiştirin; Hamilton yolu slaytındaki 5 düğümlü grafta sonuç?
- Sudoku çözücüsüne MRV (en az adaylı hücre önce) ekleyin.
- Labirent örneğinde girişten çıkışa kaç farklı basit yol vardır?
- Alt küme toplamına "kalan elemanlar yetmiyorsa kes" budamasını ekleyin.
Cevaplar / ipuçları
satir == nikensayac++; return false;→ n = 8 için 92.- 1 + 3 + 6 + 6 = 16 düğüm; 6 yaprak = 3!.
konum == nikengraf[yol[n-1]][yol[0]] == 1de istenir; 0 → 1 → 4 → 3 → 2 yolu 2 → 0 kenarıyla kapanır: döngü var.- Örnek bulmacada 51 yerleştirme, 0 geri alma (4 208 yerine).
- 1 yol: sol-alt bölge çıkmaz, yalnız üst koridor çıkışa varır.
if (toplam + kalan[i] < hedef) return false;(kalan[i]: sonek toplamı).
Özet
Kaynaklar
- Cormen, Leiserson, Rivest ve Stein, Introduction to Algorithms, 4. baskı, MIT Press, 2022.
- Levitin, Introduction to the Design and Analysis of Algorithms, 3. baskı, Pearson, 2012 (Bölüm 12: Backtracking).
- Russell ve Norvig, Artificial Intelligence: A Modern Approach, 4. baskı, 2020 (Bölüm 6: kısıt sağlama, en az çakışma).
- S. Minton, M. Johnston, A. Philips ve P. Laird, "Minimizing Conflicts: A Heuristic Repair Method for Constraint Satisfaction and Scheduling Problems", Artificial Intelligence 58, 1992.
- D. E. Knuth, The Art of Computer Programming, Cilt 4B, 2022 (Backtrack programming, Dancing Links).