N-Vezir ve Kısıt Yayılımı
Sütun ve köşegen kümelerini kullanarak kısıtları O(1) sürede kontrol edecek şekilde N×N tahtasına N vezir yerleştirin; çözümleri sayma ile listeleme arasındaki farkı tartışın.
N-Vezir ve Kısıt Yayılımı, CoddyKit'te ücretsiz bir Coding Interview Prep dersidir. Bu, 4 dersinin 4. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Coding Interview Prep öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Coding Interview Prep kursu toplamda 4 dersten oluşur.
N Vezir Problemi
N Vezirleri problemi (LeetCode 51/52), hiçbir iki vezirin birbirine saldıramayacağı şekilde N veziri N×N satranç tahtasına yerleştirmenizi ister. Vezirler satırlar, sütunlar ve her iki köşegen boyunca saldırır. N=4 için tam olarak 2 çözüm vardır. Klasik sürüm olan N=8 için 92 çözüm vardır. Bu, arama uzayını kısıt denetimiyle büyük ölçüde budayan temel geri izleme problemidir.
# N-Queens constraints:
# 1. Exactly one queen per row
# 2. No two queens in the same column
# 3. No two queens on the same diagonal (top-left to bottom-right)
# 4. No two queens on the same anti-diagonal (top-right to bottom-left)
# For N=4, the 2 solutions:
sol1 = ['.Q..', '...Q', 'Q...', '..Q.']
sol2 = ['..Q.', 'Q...', '...Q', '.Q..']
print('N=4 solutions:')
for row in sol1: print(row)
print()
for row in sol2: print(row)Her Satıra Bir Vezir Yerleştirme
Hiçbir iki vezir aynı satırı paylaşamayacağından tam olarak bir vezir her satıra yerleştirilir. Geri izleme, her satır için bir sütun seçerek satır satır özyinelemeli biçimde ilerler. Bu, vezir başına N² seçimlik arama uzayını her satır için yalnızca N sütuna indirerek N^N başlangıç dalı oluşturur; ancak kısıtlar bu sayıyı büyük ölçüde azaltır. Özyineleme derinliği N'dir (her satır için bir düzey) ve dallanma katsayısı en fazla N'dir.
def solve_n_queens(n):
results = []
queens = [] # queens[row] = column of queen in that row
def backtrack(row):
if row == n:
# Build the board representation
board = []
for r in range(n):
board.append('.' * queens[r] + 'Q' + '.' * (n - queens[r] - 1))
results.append(board)
return
for col in range(n):
if is_valid(row, col):
queens.append(col) # CHOOSE
backtrack(row + 1) # EXPLORE
queens.pop() # UNCHOOSE
def is_valid(row, col):
for r, c in enumerate(queens):
if c == col: return False # same column
if abs(row - r) == abs(col - c): return False # diagonal
return True
backtrack(0)
return results
print(len(solve_n_queens(4)), 'solutions for N=4') # 2
print(len(solve_n_queens(8)), 'solutions for N=8') # 92Kümelerle O(1) Kısıt Denetimi
Yerleştirilmiş tüm vezirleri tarayarak geçerliliği denetlemek, aday başına O(N) maliyet getirir ve en kötü durumda toplam algoritma maliyetini O(N² × N!) yapar. Üç küme tutarak her geçerlilik denetimini O(1) zamanına indirebiliriz: cols (dolu sütunlar), diag (sol üstten sağ alta köşegenler için satır-sütun değerleri) ve anti_diag (sağ üstten sol alta köşegenler için satır+sütun değerleri). Aynı köşegendeki vezirler aynı satır-sütun değerini; aynı karşı köşegendeki vezirler ise aynı satır+sütun değerini paylaşır.
def solve_n_queens_fast(n):
results = []
cols = set() # occupied columns
diag = set() # row - col (positive diagonal)
anti = set() # row + col (negative diagonal)
queens = []
def backtrack(row):
if row == n:
board = ['.' * c + 'Q' + '.' * (n-c-1) for c in queens]
results.append(board)
return
for col in range(n):
if col in cols or (row-col) in diag or (row+col) in anti:
continue # PRUNE: constraint violated
# CHOOSE
cols.add(col); diag.add(row-col); anti.add(row+col); queens.append(col)
backtrack(row + 1) # EXPLORE
# UNCHOOSE
cols.remove(col); diag.remove(row-col); anti.remove(row+col); queens.pop()
backtrack(0)
return results
print(len(solve_n_queens_fast(8))) # 92Köşegen Değişmezinin Açıklanması
Köşegenlere ilişkin temel gözlem şudur: sol üstten sağ alta uzanan aynı köşegendeki tüm hücreler aynı row - col değerine sahiptir. Örneğin (0,0), (1,1) ve (2,2) hücrelerinin tamamında row-col=0 olur. Aynı karşı köşegendeki tüm hücreler ise aynı row + col değerine sahiptir: (0,2), (1,1) ve (2,0) hücrelerinin tamamında row+col=2 olur. Bunlar, köşegen çakışmalarını O(N) doğrusal tarama yerine O(1) küme aramasıyla denetlememizi sağlayan sabit zamanlı değişmezlerdir.
# Visualise the diagonal invariants for a 4x4 board
n = 4
print('row-col values (same diagonal):')
for r in range(n):
print([r-c for c in range(n)])
print('row+col values (same anti-diagonal):')
for r in range(n):
print([r+c for c in range(n)])
# Verify: (0,0) and (2,2) share diag value 0
print('(0,0) diag:', 0-0, '| (2,2) diag:', 2-2) # both 0
# Verify: (0,2) and (2,0) share anti-diag value 2
print('(0,2) anti:', 0+2, '| (2,0) anti:', 2+0) # both 2Çözümleri Sayma: N Vezirleri II
N Vezirleri II (LeetCode 52) tahtaları değil, yalnızca çözüm sayısını ister. Bu sayede küçük bir iyileştirme yapılabilir: tahta oluşturma adımını atlayıp yalnızca bir sayacı artırınız. Kümeler yerine bit maskeleri kullanmak, sayma işlemini işlem başına neredeyse O(1) hızına çıkarabilir. Çözüm sayısı tekdüze olmayan biçimde artar: 1(N=1), 0(N=2), 0(N=3), 2(N=4), 10(N=5), 4(N=6), 40(N=7), 92(N=8).
def total_n_queens(n):
count = [0]
cols = set(); diag = set(); anti = set()
def backtrack(row):
if row == n:
count[0] += 1
return
for col in range(n):
if col in cols or (row-col) in diag or (row+col) in anti:
continue
cols.add(col); diag.add(row-col); anti.add(row+col)
backtrack(row + 1)
cols.remove(col); diag.remove(row-col); anti.remove(row+col)
backtrack(0)
return count[0]
for n in range(1, 11):
print(f'N={n}: {total_n_queens(n)} solutions')Hız için Bit Maskeli N Vezirleri
Çok büyük N değerleri için bit maskesi uygulaması önemli ölçüde daha hızlı çalışır. Üç tamsayıyı bit maskesi olarak kullanınız: cols, left_diag (her satırda sola kayar) ve right_diag (her satırda sağa kayar). Kullanılabilir sütunlar ((1<<n)-1) & ~(cols|left_diag|right_diag) ifadesiyle bulunur. Her kullanılabilir sütunu bit = available & -available (ayarlanmış en düşük bit) ile çıkarıp özyinelemeli çağrı yapınız. Bu yöntem, bit düzeyinde işlemlerle kısıt denetimi başına O(1) zaman elde eder.
def total_n_queens_bitmask(n):
full = (1 << n) - 1 # all n columns set
count = [0]
def bt(cols, left_diag, right_diag):
if cols == full:
count[0] += 1
return
available = full & ~(cols | left_diag | right_diag)
while available:
bit = available & -available # lowest set bit
available &= available - 1 # remove lowest bit
bt(cols | bit,
(left_diag | bit) << 1,
(right_diag | bit) >> 1)
bt(0, 0, 0)
return count[0]
for n in range(1, 13):
print(f'N={n}: {total_n_queens_bitmask(n)}')Kısıt Yayılımı Kavramı
Kısıt yayılımı, basit budamanın ötesine geçer: bir vezir yerleştirdikten sonra, sonraki satırlardaki tüm geçersiz konumları hemen çıkarır ve eler. Bu, her adayda geçerliliği denetlemekten daha agresiftir; dallanmadan önce arama uzayını proaktif biçimde daraltırsınız. En ünlü örnek, SAT çözücülerinde ve Sudoku çözücülerinde görülen Yay Tutarlılığıdır; burada bir rakamın yerleştirilmesi, aynı satır, sütun ve 3×3 kutudaki seçenekleri eler.
# Constraint propagation in Sudoku:
# After placing 5 in cell (0,0):
# - Row 0: no other cell can have 5
# - Column 0: no other cell can have 5
# - Box (0,0)-(2,2): no other cell can have 5
# This is propagated BEFORE branching further
# Simple demo: remaining valid columns after placing queens
def remaining_columns(n, queens):
cols = set(q for q in queens)
diags = set(r - q for r, q in enumerate(queens))
anti_diags = set(r + q for r, q in enumerate(queens))
row = len(queens)
return [c for c in range(n)
if c not in cols
and (row-c) not in diags
and (row+c) not in anti_diags]
print(remaining_columns(8, [0])) # valid cols for row 1 after placing col 0 in row 0Sudoku Çözücü
Sudoku, kısıt yayılımının klasik problemidir. Her boş hücrede geçerli rakam seçenekleri, aynı satırda, sütunda veya 3×3 kutuda zaten bulunmayan rakamlardır. Geri izlemeli çözücü şu adımları izler: ilk boş hücreyi bulur, her geçerli rakamı dener ve özyinelemeli olarak ilerler. Bir çelişkiye ulaşılırsa (geçerli rakamı olmayan boş hücre), geri izleme yapılır. İyi Sudoku çözücüleri, geri izlemeden önce kısıt yayılımını (kurşun kalem işaretleri) de uygular.
def solve_sudoku(board):
def is_valid(r, c, num):
for i in range(9):
if board[r][i] == num: return False # row
if board[i][c] == num: return False # col
br, bc = (r//3)*3, (c//3)*3
for i in range(3):
for j in range(3):
if board[br+i][bc+j] == num: return False # box
return True
def backtrack():
for r in range(9):
for c in range(9):
if board[r][c] == '.':
for d in '123456789':
if is_valid(r, c, d):
board[r][c] = d
if backtrack(): return True
board[r][c] = '.'
return False # no valid digit found
return True # no empty cells: solved
backtrack()
return board
# Mini test with a solvable board (simplified)
print('Sudoku solver implemented')En Çok Kısıtlanan Değişken Buluşsal Yöntemi
Kısıt tatmini problemleri için önemli bir optimizasyon: her zaman en çok kısıtlanan değişkeni (en az geçerli seçeneğe sahip hücreyi) seçin. Sudoku'da bir hücrede yalnızca 1 geçerli rakam varsa, onu hemen doldurmak zorunludur; geri izleme gerekmez. Bu tür hücreleri önce seçmek, arama ağacının derinliğini büyük ölçüde azaltır. Bu, yapay zekâdaki kısıt programlamasında kullanılan Minimum Kalan Değerler (MRV) buluşsal yöntemidir.
def solve_sudoku_mrv(board):
'''Find cell with fewest valid choices (MRV heuristic).'''
def valid_choices(r, c):
nums = set('123456789')
for i in range(9):
nums.discard(board[r][i])
nums.discard(board[i][c])
br, bc = (r//3)*3, (c//3)*3
for i in range(3):
for j in range(3):
nums.discard(board[br+i][bc+j])
return nums
def find_mrv():
best = (10, -1, -1, set()) # (choices_count, r, c, choices)
for r in range(9):
for c in range(9):
if board[r][c] == '.':
choices = valid_choices(r, c)
if len(choices) < best[0]:
best = (len(choices), r, c, choices)
return best[1], best[2], best[3]
def backtrack():
r, c, choices = find_mrv()
if r == -1: return True # no empty cells
for d in choices:
board[r][c] = d
if backtrack(): return True
board[r][c] = '.'
return False
backtrack()
return boardN-Vezir Çözüm Sayıları Tablosu
N-vezir çözümlerinin sayısı şu iyi bilinen diziyi izler: N=1: 1, N=2: 0, N=3: 0, N=4: 2, N=5: 10, N=6: 4, N=7: 40, N=8: 92, N=9: 352, N=10: 724. Bilinen bir kapalı biçimli formül yoktur; sayının hesaplanması gerekir. N=27 için yaklaşık 2.34 × 10^17 çözüm vardır. Mülakat soruları genellikle N ≤ 9 için sorulur. Üstel büyümeyi anlamak, daha büyük N değerlerinde bit maskesi optimizasyonunun neden önemli olduğunu açıklar.
def count_queens(n):
'''O(1) per constraint check using sets.'''
count = [0]
cols = set(); diag = set(); anti = set()
def bt(row):
if row == n: count[0] += 1; return
for col in range(n):
if col in cols or (row-col) in diag or (row+col) in anti: continue
cols.add(col); diag.add(row-col); anti.add(row+col)
bt(row+1)
cols.discard(col); diag.discard(row-col); anti.discard(row+col)
bt(0)
return count[0]
sequence = [count_queens(n) for n in range(1, 12)]
print('N-Queens counts:', sequence)
# [1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680]N-Vezir Tahtası Oluşturma
Görüşmeci gerçek tahtaları (LeetCode 51) döndürmenizi istediğinde, her tahtayı queens listesinden oluşturun; burada queens[r], r satırındaki vezirin sütunudur. Dize oluşturma işlemi: her satır için '.' * col + 'Q' + '.' * (n - col - 1). O(n²) olan bu oluşturma işlemi yalnızca özyineleme ağacının yapraklarında (tüm N vezir yerleştirildiğinde) çağrılır; bu nedenle toplam karmaşıklığı etkilemez.
def n_queens_boards(n):
results = []
queens = []
cols = set(); diag = set(); anti = set()
def build_board():
return ['.' * c + 'Q' + '.' * (n-c-1) for c in queens]
def bt(row):
if row == n:
results.append(build_board())
return
for col in range(n):
if col in cols or (row-col) in diag or (row+col) in anti: continue
cols.add(col); diag.add(row-col); anti.add(row+col); queens.append(col)
bt(row+1)
cols.remove(col); diag.remove(row-col); anti.remove(row+col); queens.pop()
bt(0)
return results
for board in n_queens_boards(4):
for row in board: print(row)
print()Hızlı Kontrol
Bu dersteki Veri Yapıları & Algoritmalar — Kodlama Mülakatı Hazırlığı kavramlarını ne kadar anladığınızı sınayın.
Ders Özeti
Bu derste şunları öğrendiniz: N-Vezir probleminde her satıra bir vezir yerleştirilir ve O(1) kısıt denetimi için sütunlarda, köşegenlerde (satır-sütun) ve karşı köşegenlerde (satır+sütun) kümeler kullanılır; bit maskeleri, kısıt denetimlerini daha da hızlandırır ve tüm yerleşimleri işlem başına yaklaşık O(1) sürede keşfetmeyi sağlar; ayrıca kısıt yayılımı (MRV buluşsal yöntemi), her seferinde en çok kısıtlanan değişkeni seçerek aramayı azaltır. Sırada Açgözlü ve DP yaklaşımlarını karşılaştıracak ve her birini ne zaman uygulayacağınızı öğreneceksiniz.
Sıkça Sorulan Sorular
“N-Vezir ve Kısıt Yayılımı” dersi ücretsiz mi?
Evet — “N-Vezir ve Kısıt Yayılımı” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Coding Interview Prep kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Coding Interview Prep kursu toplamda 4 dersten oluşur.
“N-Vezir ve Kısıt Yayılımı” dersinde ne öğreneceğim?
Sütun ve köşegen kümelerini kullanarak kısıtları O(1) sürede kontrol edecek şekilde N×N tahtasına N vezir yerleştirin; çözümleri sayma ile listeleme arasındaki farkı tartışın. Coding Interview Prep ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
Coding Interview Prep öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te Coding Interview Prep, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 4. dersidir.
“N-Vezir ve Kısıt Yayılımı” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu Coding Interview Prep dersinde kod yazıp çalıştırabilir miyim?
Evet. Her Coding Interview Prep dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- Geri İzleme Şablonu: Seç, Keşfet, Seçimi Geri Al
- Alt Kümeler ve Kuvvet Kümesi
- Permütasyonlar ve Kombinasyonlar
- N-Vezir ve Kısıt Yayılımı