Complete search
August 22, 2018
Generating subsets
Alternatively choose to include and not include element from array and branch (making sure to undo the last move after both branches).
def all_subsets(A):
n = len(A)
subset = []
def search(k):
if k == n:
print(subset)
else:
# don't push
search(k+1)
subset.append(A[k])
search(k+1)
# undo push
subset.pop()
search(0)
Generating permutations
Given a substring that is the last permutation (lexically last) change that string the least; i.e. swap the next character into the smallest place it can go and then reverse the string.
def next_perm(A):
n = len(A)
# find longest tail weakly decreasing
i = n - 1
while i-1 > 0 and A[i-1] >= A[i] :
i -= 1
# A[i-1] < A[i]
j = i-1
while i < n and A[j] <= A[i]:
i += 1
# A[j] > A[i] so swap
A[j], A[i-1] = A[i-1], A[j]
# now reverse
return A[:j+1] + reversed(A[j+1:])
N Queens
Place $n$ queens on an $n \times n$ chessboard without any attacking any of the others.
Knowing which diagonal you’re is the only tricky part. To figure it out flip the diag1
and diag2
grids and compute
manhattan distance from the 0
(this will give the lines of equidistance i.e. diagonals in manhattan metric).
def nqueens(n):
column = n*[0]
diag1 = (2*n-1)*[0]
diag2 = (2*n-1)*[0]
count = 0
def search(y):
if y == n:
count += 1
return
# iterate over the columns to look for a potential position
for x in range(n):
# (x,y) is on antidiagonal x+y and diagonal (n-1-y+x)
if column[x] or diag1[x+y] or diag2[n-1-y+x]: continue
column[x] = diag1[x+y] = diag2[n-1-y+x] = 1
search(y+1)
column[x] = diag1[x+y] = diag2[n-1-y+x] = 0