“芬兰数学家因卡拉,花费3个月时间设计出了世界上迄今难度最大的数独游戏,而且它只有一个答案。因卡拉说只有思考能力最快、头脑最聪明的人才能破解这个游戏。”这是英国《每日邮报》2012年6月30日的一篇报道。看完这个新闻就对数独有点感兴趣了,于是用python解一下玩玩,无意中却戳穿了某个虚假新闻(下面有链接)。

python解数独--世界最难数独2.3秒完成_数独

        上图就是那个最难数独。解数独用的就是深度优先搜索,有几个方面可以优化一下提高速度:

        1.把每个空格的可能的点先列举出来,因为深搜是把遍历的值写入sudoku矩阵再判断,如果不列举可能的值,那就只能用0-9遍历,这样效率会降低,如果空格较少的情况下,先把可能的点列举出来会使速度翻倍;

        2.每次把可能情况最少的点优先尝试写入值判断,这个我在程序里没有加,因为深搜的每个树节点必须是固定的,这样当退栈返回上一结点的时候才能正确返回,而我加了这个判断最优节点功能的代码中,返回的树节点不是固定的,因为随着数独空格中值的填入,矩阵也发生着变化,每个点的优先级也在同时发生着变化,这样逻辑就乱了,但我觉得还是可以加上的,这里也算一个小遗憾,希望感兴趣的大牛加上这个功能,那速度又是一番提升。

        好了,代码如下:





import time

t0=time.time()

class point:

def __init__(self,x,y):

self.x=x

self.y=y

self.available=[]

self.value=0

 

def rowNum(p,sudoku):

row=set(sudoku[p.y*9:(p.y+1)*9])

row.remove(0)

return row #set type

 

def colNum(p,sudoku):

col=[]

length=len(sudoku)

for i in range(p.x,length,9):

col.append(sudoku[i])

col=set(col)

col.remove(0)

return col #set type

 

def blockNum(p,sudoku):

block_x=p.x//3

block_y=p.y//3

block=[]

start=block_y*3*9+block_x*3

for i in range(start,start+3):

block.append(sudoku[i])

for i in range(start+9,start+9+3):

block.append(sudoku[i])

for i in range(start+9+9,start+9+9+3):

block.append(sudoku[i])

block=set(block)

block.remove(0)

return block #set type

 

def initPoint(sudoku):

pointList=[]

length=len(sudoku)

for i in range(length):

if sudoku[i]==0:

p=point(i%9,i//9)

for j in range(1,10):

if j not in rowNum(p,sudoku) and j not in colNum(p,sudoku) and j not in blockNum(p,sudoku):

p.available.append(j)

pointList.append(p)

return pointList

 

 

def tryInsert(p,sudoku):

availNum=p.available

for v in availNum:

p.value=v

if check(p,sudoku):

sudoku[p.y*9+p.x]=p.value

if len(pointList)<=0:

t1=time.time()

useTime=t1-t0

showSudoku(sudoku)

print('\nuse Time: %f s'%(useTime))

exit()

p2=pointList.pop()

tryInsert(p2,sudoku)

sudoku[p2.y*9+p2.x]=0

sudoku[p.y*9+p.x]=0

p2.value=0

pointList.append(p2)

else:

pass

 

def check(p,sudoku):

if p.value==0:

print('not assign value to point p!!')

return False

if p.value not in rowNum(p,sudoku) and p.value not in colNum(p,sudoku) and p.value not in blockNum(p,sudoku):

return True

else:

return False

 

def showSudoku(sudoku):

for j in range(9):

for i in range(9):

print('%d '%(sudoku[j*9+i]),end='')

print('')

 

if __name__=='__main__':

sudoku=[

8,0,0,0,0,0,0,0,0,

0,0,3,6,0,0,0,0,0,

0,7,0,0,9,0,2,0,0,

0,5,0,0,0,7,0,0,0,

0,0,0,0,4,5,7,0,0,

0,0,0,1,0,0,0,3,0,

0,0,1,0,0,0,0,6,8,

0,0,8,5,0,0,0,1,0,

0,9,0,0,0,0,4,0,0,

]

pointList=initPoint(sudoku)

showSudoku(sudoku)

print('\n')

p=pointList.pop()

tryInsert(p,sudoku)


  我用time计时的起始时间是从第一行import time模块之后就开始了,这样测出的时间是最长的吧~哈~运行结果如下:


python解数独--世界最难数独2.3秒完成_数独_02

转载请注明: 转自 http://blog.csdn.net/littlethunder/article/details/9749509