N-Vezir Problemi

n veziri birbirini tehdit etmeyecek şekilde tahtaya yerleştiren, çıkmazda geri dönen klasik geri izleme problemi.

Önce bunlara göz at

#Nasıl çalışır?

Geri izleme (backtracking), bir çözümü adım adım kuran ve bir adımın çözüme götürmeyeceği anlaşılınca o adımı geri alıp başka bir seçeneği deneyen bir arama tekniğidir. Tüm olasılıkları körü körüne denemek yerine, umutsuz dalları erkenden budar.

N-Vezir problemi bunun klasik örneğidir: n × n bir satranç tahtasına n vezir, hiçbiri diğerini tehdit etmeyecek şekilde yerleştirilmelidir. Vezir aynı satır, sütun ve çaprazdaki her taşı tehdit eder.

Her satıra tam bir vezir gelmesi gerektiği için satır satır ilerlenir. Bir satırda, yukarıdaki vezirlerin tehdit etmediği ilk sütuna vezir konur ve sonraki satıra geçilir. Bir satırda güvenli sütun kalmazsa önceki satırdaki vezir kaldırılır ve bir sonraki sütunu denenir.

8 × 8 tahtada 92 çözüm vardır. Vezirleri rastgele 64 kareye dağıtmanın 4 milyardan fazla yolu varken geri izleme yalnızca birkaç bin kare dener.

#Kendin dene

$ n_queens --interactive

n × n tahtaya n vezir, hiçbiri diğerini tehdit etmeyecek şekilde yerleştirilecek: aynı sütunda ya da çaprazda iki vezir olamaz. Her satıra bir vezir koyup çıkmazda geri dönüyoruz.

GeziliyorYeniÇıkarılıyorBulundu / okunan

#Adım adım

  1. 01İlk satırdan başla.
  2. 02Satırdaki her sütun için: yukarıdaki bir vezir bu kareyi tehdit ediyorsa atla.
  3. 03Güvenliyse vezir koy ve sonraki satıra geç; son satır da dolduysa çözüm bulundu.
  4. 04Bir satırda güvenli kare kalmazsa geri dön: önceki satırın vezirini kaldır ve oradaki sonraki sütunu dene.

#Örnek kod

Aynı algoritma 8 dilde. Her program derlenip çalıştırılarak test edildi ve hepsi aynı çıktıyı veriyor.

def solve(n: int):
    """First solution as a list of columns (one per row), or None."""
    queens = []  # queens[row] = column

    def safe(row: int, col: int) -> bool:
        return all(c != col and abs(c - col) != row - r for r, c in enumerate(queens))

    def place(row: int) -> bool:
        if row == n:
            return True
        for col in range(n):
            if safe(row, col):
                queens.append(col)
                if place(row + 1):
                    return True
                queens.pop()  # dead end: backtrack
        return False

    return queens if place(0) else None


def count(n: int) -> int:
    """All solutions, with sets of used columns and diagonals for O(1) checks."""
    cols, diag1, diag2 = set(), set(), set()

    def place(row: int) -> int:
        if row == n:
            return 1
        total = 0
        for col in range(n):
            if col in cols or row - col in diag1 or row + col in diag2:
                continue
            cols.add(col)
            diag1.add(row - col)
            diag2.add(row + col)
            total += place(row + 1)
            cols.remove(col)
            diag1.remove(row - col)
            diag2.remove(row + col)
        return total

    return place(0)


print(" ".join(str(c + 1) for c in solve(4)))  # 1-based columns by row
print(count(8))

#Karmaşıklık

İşlemSüre
En kötü durum (budamasız)O(n!)
Bir karenin güvenliğini kontrolO(n), sütun/çapraz kümeleriyle O(1)
BellekO(n)
8 × 8 için denenen karebirkaç bin

Her satıra bir vezir koymak arama alanını nⁿ'den n!'e indirir; tehdit kontrolüyle budama bunu çok daha aşağı çeker. Sütunlar ve iki çapraz yönü için üç boolean dizi tutulursa her kontrol O(1) olur. Bit maskeleriyle n = 15 civarına kadar tüm çözümler hızla sayılabilir.

#Ne zaman kullanılır?

Geri izleme; Sudoku, bulmacalar, labirent çözme, kısıt sağlama problemleri (ders programı, sınav takvimi), graf boyama ve kombinasyon üretme gibi "kısıtları sağlayan bir yerleşim bul" problemlerinin genel çözüm kalıbıdır.

#Alıştırma

Soruları cevaplamak ve ilerlemeni kaydetmek için giriş yap.

Kolay

1/3

Geri izleme (backtracking) bir çıkmaza girince ne yapar?

  • 1Son seçimi geri alıp başka bir seçeneği dener
  • 2Baştan başlar
  • 3Rastgele bir seçim yapar
  • 4Durur ve çözüm yok der

Orta

1/1

Satır r, sütun c'deki bir vezirle satır r2, sütun c2'deki bir vezir aynı çaprazda mıdır? Hangi koşul bunu söyler?

  • 1|c − c2| = |r − r2|
  • 2c + c2 = r + r2
  • 3c = c2
  • 4r · c = r2 · c2

Zor

1/1

Her satıra yalnızca bir vezir koymak arama alanını nasıl küçültür?

  • 1n² kare arasından seçimi n! ya da daha azına indirir; budama ile daha da azalır
  • 2Hiç değiştirmez
  • 3Arama alanını ikiye böler
  • 4Yalnızca bellek kullanımını azaltır

#Bundan sonra

Bu dersi bildiğini varsayan dersler: