I am trying to solve the n-queens problem. I wrote a solution for the problem as follows:
def isSafe(board,row,col):
for i in range(row):
if board[i][col]==1:
return False
x,y = row,col
# print(x,y)
while x>=0 and y>=0:
if board[x][y]==1:
return False
x-=1
y-=1
x,y = row,col
# print(x,y)
while x>=0 and y<len(board):
if board[x][y]==1:
return False
x-=1
y+=1
return True
def solveNQueens(n):
ans = []
def placeQueens(board,row):
if row==len(board):
ans.append(board)
return
for i in range(len(board)):
if isSafe(board,row,i):
board[row][i]=1
# print(board)
placeQueens(board,row+1)
board[row][i]=0
return
board = [[0 for i in range(n)] for j in range(n)]
# print(board)
placeQueens(board,0)
print(ans)
solveNQueens(4)
The above code uses recursive backtracking to solve the n queens problem. The placeQueens function appends the board combination directly to ans list when all the queens are assigned a row but when I try to print ans, all the places are marked as zeroes.
e.g for n=4:
Expected ans = [[[0,1,0,0],[0,0,0,1],[1,0,0,0],[0,0,1,0]],[[0,0,1,0],[1,0,0,0],[0,0,0,1],[0,1,0,0]]]
Answer printed = [[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]]
Where am I going wrong??
I tried appending the board positions one by one to the ans list and the code works fine.
def isSafe(board,row,col):
for i in range(row):
if board[i][col]==1:
return False
x,y = row,col
# print(x,y)
while x>=0 and y>=0:
if board[x][y]==1:
return False
x-=1
y-=1
x,y = row,col
# print(x,y)
while x>=0 and y<len(board):
if board[x][y]==1:
return False
x-=1
y+=1
return True
def solveNQueens(n):
ans = []
def placeQueens(board,row):
if row==len(board):
ans.append([])
# print(board)
for i in range(len(board)):
ans[-1].append([])
for j in board[i]:
if j==0:
ans[-1][-1].append(0)
else:
ans[-1][-1].append(1)
return
for i in range(len(board)):
if isSafe(board,row,i):
board[row][i]=1
# print(board)
placeQueens(board,row+1)
board[row][i]=0
return
board = [[0 for i in range(n)] for j in range(n)]
# print(board)
placeQueens(board,0)
print(ans)
solveNQueens(4)
Why is the first code generating incorrect output, when both the codes are logically similar??
So, you have, correctly, avoided the trap that arrays are "pointers" (see note at last paragraph), and therefore that using several time the same array would make all the instance alias of each other here:
You were right to do so. The trap here would have been to say
Note that the inner
[0]*nwould not have been a problem. But the outer one, would have lead to the well known situation where changingboard[1][2]=1for example, would have changedboardto[[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], because allboard[i]are the same array of ints.Reason why I take time to explain you something you apparently already know, and to explain a mistake you haven't made, is that this is the same reason why your code doesn't work. Because "arrays are pointers".
So, here
what you append here is
board. An array. So a "pointer". Ifboardcontent change after that, it will impact the content of what you have added toans. So the content ofans. Each thing you appended toans, are just several time the sameboard(so, even if it were not full 0, you were doomed to have only identical boards inans). And even more, since at the end of your code,boardis full 0, well ans if several timesboard, that is several timefull 0.Just, replace
by
(or
ans.append([x.copy() for x in board]), but the double loop has the advantage to resemble what you did for initialization)So to add to ans not
boardbut a new array whose content is the same asboardcontent (and that will not change whenboardchanges), and the result is (I've just tried, with your first code, and only this change)That is exactly what you were expecting.
So, your code (the recursive search, and all) works exactly as intended. Your only problem was a "pointer" problem
Note: when I say "pointer" it is by analogy with some other languages were you can use "pointer" to creates some sort of alias of a variable. In reality it is not accurate to say thing like "arrays are pointers". It is not like not all data type behave the same in python from this point of view. There aren't some data-type that are aliased and other that are copied. It is just that you wouldn't have made this mistake with, for example a string, simply because string being unmutable, if board had been a string, it couldn't have changed.
I ranted a while on this matter in another post