我在https://brilliant.org/wiki/recursive-backtracking/
找到了这段代码from itertools import *
from copy import copy
def is_distinct( list ):
'''Auxiliary function to is_solved
checks if all elements in a list are distinct
(ignores 0s though)
'''
used = []
for i in list:
if i == 0:
continue
if i in used:
return False
used.append(i)
return True
def is_valid( brd ):
'''Checks if a 3x3 mini-Sudoku is valid.'''
for i in range(3):
row = [brd[i][0],brd[i][1],brd[i][2]]
if not is_distinct(row):
return False
col = [brd[0][i],brd[1][i],brd[2][i]]
if not is_distinct(col):
return False
return True
def solve( brd , empties = 9):
'''
Solves a mini-Sudoku
brd is the board
empty is the number of empty cells
'''
if empties == 0:
#Base case
return is_valid( brd )
for row,col in product(range(3),repeat=2):
#Run through every cell
cell = brd[row][col]
if cell != 0:
#If its not empty jump
continue
brd2 = copy( brd )
for test in [1,2,3]:
brd2[row][col] = test
if is_valid(brd2) and solve(brd2,empties-1):
return True
#BackTrack
brd2[row][col] = 0
return False
Board = [ [ 0 , 0 , 0 ],
[ 1 , 0 , 0 ],
[ 0 , 3 , 1 ] ]
solve( Board , 9 - 3 )
for row in Board:#Prints a solution
print row
它返回正确的结果,表示已解决的板。
我不明白的是,solved()
递归函数修改了Board
列表,但该函数从不写入brd
,它只写入brd2
},这是一个副本。
但是,当列表最后打印时,它会显示它已写入。
所以我对这段代码感到有点困惑,我知道python函数通过引用传递列表,但是这个例子明确地使用了copy()
。我对复制感到困惑或者遗漏了什么。
答案 0 :(得分:2)
copy.copy
制作浅拷贝。在您的情况下,您有一个列表列表,浅拷贝只是创建一个新列表,但所有元素(内部列表)仍然引用旧列表:
>>> a = [[1,2,3], [2,3,1], [3,1,2]]
>>> b = copy(a)
>>> b[0][0] = 100
>>> a
[[100, 2, 3], [2, 3, 1], [3, 1, 2]]
>>> b
[[100, 2, 3], [2, 3, 1], [3, 1, 2]])
在这种情况下,如果你根本不复制它甚至可以工作,例如
brd2 = brd
一般情况下,您可以使用deepcopy
解决此问题,无需回溯或回溯但无需复制。但是复制和回溯相结合似乎有点浪费。
答案 1 :(得分:0)
您正在创建浅副本 浅拷贝就像你有一个物体,它有对其他物体的引用 因此,如果复制主对象,则尚未复制其内部引用。它仍然指向与前主对象相同的对象。
详细了解HERE
浅层复制和深层复制之间的区别仅与复合对象(包含其他对象的对象,如列表或类实例)相关:
浅复制构造一个新的复合对象,然后(尽可能)将对它的引用插入到原始对象中。
深层复制构造一个新的复合对象,然后递归地将原件中的对象的副本插入其中。