我试图验证列矩阵中是否已经存在列表中的数字,但仍在重复。有人可以帮我吗?
import random
numbers = [1,2,3,4,5,6,7,8,9]
matrix = [[None for i in range(9)] for j in range(9)]
def createMatrix():
for i in range(9):
for j in range(9):
cop = numbers[:]
random.shuffle(cop)
while matrix[i][j] is None:
temp = veriCol(matrix, j, cop)
if temp == 0:
matriz[i] = cop
else:
return None
def veriCol(matrix, col, value):
tmp = 0
for l in range(9):
#print("Vc {}".format(l)),
if value == matrix[l][col]:
tmp = 1
return tmp
createMatrix()
for i in range(9):
print(matriz[i])
答案 0 :(得分:0)
忘记索引循环,除非您需要索引用于其他目的。包含列表推导和for .. in
循环。
def is_number_in_column(number, column, matrix):
return any(row[column] == number for row in matrix)
如果您的任务是放置数字,以使任何列中都没有重复的数字,请考虑记住用完的列。
等等;将其公式化为一般情况,您当前的算法就更容易了。使用集合而不是列表会有所帮助。
答案 1 :(得分:0)
您可以维护一组使用的列值的列表。新“改组”行的验证可以更直接地完成。对于子矩阵组也是如此,尽管您需要使用间接(或复杂的索引计算)将位置映射到组集:
import random
def createMatrix():
matrix = []
numbers = [1,2,3,4,5,6,7,8,9]
groups = [ [0,0,0, 1,1,1, 2,2,2] ] * 3
groups += [ [3,3,3, 4,4,4, 5,5,5] ] * 3
groups += [ [6,6,6, 7,7,7, 8,8,8] ] * 3
while len(matrix) < 9:
matrix = []
colSets = [ set() for _ in range(9) ]
groupSets = [ set() for _ in range(9) ]
for row in range(9):
for _ in range(133496): # try multiple permutations for row (36.79%)
random.shuffle(numbers)
if any( n in used for n,used in zip(numbers,colSets) ):
continue # column conflict
if any( n in groupSets[g] for n,g in zip(numbers,groups[row]) ):
continue # sub-matrix group conflict
matrix.append(numbers.copy())
for n,used in zip(numbers,colSets): used.add(n)
for n,g in zip(numbers,groups[row]): groupSets[g].add(n)
break
if len (matrix) == row: break # restart if failed to produce a row
return matrix
sudoku = createMatrix()
for line in sudoku:
print(line)
如果您尝试生成随机的拉丁方,则更快的技术是随机分配工作基线,而不是在试验/错误过程中反复检查随机数集的有效性:
import random
numbers = random.sample(range(1,10),9)
cols = random.sample(range(9),9)
rows = random.sample(range(9),9)
matrix = [[numbers[(r+c)%9] for c in cols] for r in rows]
for line in matrix: print(line)
[8, 9, 1, 7, 6, 4, 5, 3, 2]
[5, 2, 9, 6, 4, 3, 1, 8, 7]
[2, 4, 6, 8, 5, 1, 7, 9, 3]
[1, 7, 2, 4, 3, 8, 9, 5, 6]
[7, 3, 4, 5, 1, 9, 6, 2, 8]
[3, 1, 5, 2, 7, 6, 8, 4, 9]
[4, 5, 8, 9, 2, 7, 3, 6, 1]
[9, 6, 7, 3, 8, 5, 2, 1, 4]
[6, 8, 3, 1, 9, 2, 4, 7, 5]
为解释这一点,最好从一个简单的顺序索引矩阵开始,在该矩阵中,每行比上一行偏移一个:
matrix = [ [(r+c)%9 for c in range(9)] for r in range(9) ]
[0, 1, 2, 3, 4, 5, 6, 7, 8] # base row
[1, 2, 3, 4, 5, 6, 7, 8, 0] # offset by 1
[2, 3, 4, 5, 6, 7, 8, 0, 1] # offset by 2
[3, 4, 5, 6, 7, 8, 0, 1, 2] # ....
[4, 5, 6, 7, 8, 0, 1, 2, 3]
[5, 6, 7, 8, 0, 1, 2, 3, 4]
[6, 7, 8, 0, 1, 2, 3, 4, 5]
[7, 8, 0, 1, 2, 3, 4, 5, 6]
[8, 0, 1, 2, 3, 4, 5, 6, 7]
如您所见,每行的索引为0到8(因此没有重复),每列的索引也为0到8(由于偏移而没有重复)。
现在,如果我们创建一个从1到9的数字列表并对其进行混洗,则可以将矩阵中的索引替换为混洗列表中的相应数字。由于每个索引都映射到不同的数字,因此生成的矩阵在行或列上将没有任何重复。
numbers = random.sample(range(1,10),9) # [1, 5, 9, 8, 3, 7, 6, 2, 4]
matrix = [ [numbers[i] for i in row] for row in matrix ]
[1, 5, 9, 8, 3, 7, 6, 2, 4]
[5, 9, 8, 3, 7, 6, 2, 4, 1]
[9, 8, 3, 7, 6, 2, 4, 1, 5]
[8, 3, 7, 6, 2, 4, 1, 5, 9]
[3, 7, 6, 2, 4, 1, 5, 9, 8]
[7, 6, 2, 4, 1, 5, 9, 8, 3]
[6, 2, 4, 1, 5, 9, 8, 3, 7]
[2, 4, 1, 5, 9, 8, 3, 7, 6]
[4, 1, 5, 9, 8, 3, 7, 6, 2]
最后,我们可以对行进行混排以获得矩阵的更随机组织
random.shuffle(matrix)
[5, 9, 8, 3, 7, 6, 2, 4, 1]
[9, 8, 3, 7, 6, 2, 4, 1, 5]
[1, 5, 9, 8, 3, 7, 6, 2, 4]
[7, 6, 2, 4, 1, 5, 9, 8, 3]
[2, 4, 1, 5, 9, 8, 3, 7, 6]
[6, 2, 4, 1, 5, 9, 8, 3, 7]
[4, 1, 5, 9, 8, 3, 7, 6, 2]
[8, 3, 7, 6, 2, 4, 1, 5, 9]
[3, 7, 6, 2, 4, 1, 5, 9, 8]
和列:
cols = random.sample(range(9),9) # [7, 4, 3, 0, 8, 1, 2, 5, 6]
matrix = [[matrix[r][c] for c in cols] for r in range(9)]
[4, 7, 3, 5, 1, 9, 8, 6, 2]
[1, 6, 7, 9, 5, 8, 3, 2, 4]
[2, 3, 8, 1, 4, 5, 9, 7, 6]
[8, 1, 4, 7, 3, 6, 2, 5, 9]
[7, 9, 5, 2, 6, 4, 1, 8, 3]
[3, 5, 1, 6, 7, 2, 4, 9, 8]
[6, 8, 9, 4, 2, 1, 5, 3, 7]
[5, 2, 6, 8, 9, 3, 7, 4, 1]
[9, 4, 2, 3, 8, 7, 6, 1, 5]
(上述)解决方案将这些步骤合并为一个列表理解,但使用的方法完全相同。
使用这种方法,还可以生成随机数独板(具有3x3块约束)。偏移量的公式有点复杂,行和列的混排只能在块组内和块组之间进行,但总体技术是相同的。
from random import sample
base = 3 # Will generate any size of random sudoku board instantly
side = base*base
nums = sample(range(1,side+1),side) # random numbers
board = [[nums[(base*(r%base)+r//base+c)%side] for c in range(side) ] for r in range(side)]
rowGr = sample(range(base),base) # random rows/horizontal blocks
rows = [ r for g in rowGr for r in sample(range(g*base,(g+1)*base),base) ]
colGr = sample(range(base),base) # random column/vertical blocks
cols = [ c for g in colGr for c in sample(range(g*base,(g+1)*base),base) ]
board = [[board[r][c] for c in cols] for r in rows]
for line in board:print(line)
[7, 5, 3, 6, 9, 4, 1, 2, 8]
[6, 9, 4, 1, 2, 8, 7, 5, 3]
[1, 2, 8, 7, 5, 3, 6, 9, 4]
[2, 8, 7, 5, 3, 6, 9, 4, 1]
[5, 3, 6, 9, 4, 1, 2, 8, 7]
[9, 4, 1, 2, 8, 7, 5, 3, 6]
[8, 7, 5, 3, 6, 9, 4, 1, 2]
[3, 6, 9, 4, 1, 2, 8, 7, 5]
[4, 1, 2, 8, 7, 5, 3, 6, 9]
这会在0.2毫秒内生成9x9随机数独,而尝试/错误方法则需要1到20秒(非常随机的时间)
类似于拉丁方形技术,它基于有效的基线板,该基线板由具有适当的行,列和块约束的索引组成:
base = 3
side = base*base
board = [[(base*(r%base)+r//base+c)%side for c in range(side)] for r in range(side)]
for line in board: print(line)
[0, 1, 2, 3, 4, 5, 6, 7, 8] # base row
[3, 4, 5, 6, 7, 8, 0, 1, 2] # offset by 3
[6, 7, 8, 0, 1, 2, 3, 4, 5] # offset by 6
[1, 2, 3, 4, 5, 6, 7, 8, 0] # offset by 1
[4, 5, 6, 7, 8, 0, 1, 2, 3] # offset by 4
[7, 8, 0, 1, 2, 3, 4, 5, 6] # offset by 7
[2, 3, 4, 5, 6, 7, 8, 0, 1] # offset by 2
[5, 6, 7, 8, 0, 1, 2, 3, 4] # offset by 5
[8, 0, 1, 2, 3, 4, 5, 6, 7] # offset by 8
其余的只是用改编的数字替换索引以及改写行的列和块。