如何用python计算数独_用python解决数独

本文介绍了用Python解决9x9数独问题的思路和步骤,包括复制数独、按行、列和小矩阵生成新数独,以及填充可能的数值。通过遍历和求交集来缩小可能值范围,递归更新数独。提供的代码实现了基本的数独解算,但仅适用于较简单的数独题目。
摘要由CSDN通过智能技术生成

看到了,季以安:用Python解数独[0],写得很详细,我没有全部看完,借用他的思路,我也来试试,回头再去看他怎么弄,特别是递归的实现方式。

先上思路:

'''1.解9*9数独的思路:(1)一个单元格的推理:根据行、列、小矩阵得出该单元格有可能填入的数值的三个列表;求并集,缩小范围,简单的题目好多单元格都能得到唯一值。(2)重复上面这个过程2.实现:(1)复制生成三个新数独(按行、按列、按小矩阵)(2)把上述三个数独每个空单元格内填满’有可能‘的数值(用列表填入)(3)遍历每个空单元格,去找这个单元格分别是三个新数独的哪个位置(是三个列表-求交集)(4)更新原数独,递归更新后的数独(5)我也知道这个程序思路,只能做比较简单的数独,就是练练,写得好会考虑怎么解高等级数独。'''图一:数独就是一个二维列表,用过xlwings操作过excel的很好理解 以下考虑算法的时候就看着这张图就行了

思路确定后,来定一下程序大致的框架:

soduku1 #待求解的数独

soduku2 #复制soduku1,然后遍历空单元格,按行来确定该单元格可能填入哪些值(一个列表),

全算出来后就是一个新数独(思路不断在二维列表和图一之间切换)

soduku3 #和上面一样,按列,基本相同,

soduku4 #按小矩阵,实现需要计算思考

A:def 复制待解数独(soduku1):

# 1.因为soduku1是有用的,不要去修改,所以复制

# 2.soduku2,soduku3的结构是一样的,所有写在一起

# 3.按行生成soduku2很简单,就是单纯的复制soduku1,只不过因为是二维列表,

要用copy.deepcopy(soduku1)才有用,不能soduku2=soduku1[:],更不能

soduku2=soduku1这么粗暴

# 4.按列生成soduku3,复杂一点,这里是框架,先不说

return newsodu

B:def 按待解数独生成小矩阵数独(soduku1):

#这个需要一点观察,还需要一点小学水平算法

return newsodu

C:def 把新生成的三个数组空格全填满(sodu):

#看图方式:cells(0,0)(看图一,这个表示第0行,第0列,即第一个

单元格,后面都采取这样的方式看图)

# soduku2的cells(0,0)会被填入[2,4,5,6],表示按行第一个单元格可能是2,4,5,6

# 全填满无非是循环

# 分别传入参数soduku2,soduku3,soduku4,就会得到三个填满的新数独

return 填满的三个新数独

def 重复算():

调用C:分别传入soduku2,soduku3,soduku4

烂尾了,本来想一步步写思路,没耐心写了,好像也不太有人看,看别人代码有时是很难受的,直接上代码,基本思路注释里还是有的。

'''1.解9*9数独的思路:(1)一个单元格的推理:根据行、列、小矩阵得出该单元格有可能填入的数值的三个列表;求并集,缩小范围,简单的题目好多单元格都能得到唯一值。(2)重复上面这个过程2.实现:(1)复制生成三个新数独(按行、按列、按小矩阵)(2)把上述三个数独每个空单元格内填满’有可能‘的数值(用列表填入)(3)遍历每个空单元格,去找这个单元格分别是三个新数独的哪个位置(是三个列表-求交集),简单的题目这一步就能得到一个唯一值(4)更新原数独,递归更新后的数独(5)我也知道这个程序思路,只能做比较简单的数独,就是练练,写得好会考虑怎么解高等级数独。'''

import copy

import numpy as np

import xlwings as xw

soduku = [[] for i in range(9)]

soduku[0] = ['',8,9,1,'',3,'','','']

soduku[1] = ['',2,7,4,'','',8,'','']

soduku[2] = ['','','',5,2,'','','','']

soduku[3] = ['',7,6,9,'','',5,'',8]

soduku[4] = [8,'',3,6,'',1,2,'','']

soduku[5] = ['',4,5,3,8,7,1,6,'']

soduku[6] = [7,'',8,2,1,4,3,9,5]

soduku[7] = [9,3,1,7,6,5,4,'',2]

soduku[8] = [4,'',2,'','',9,'','',6]

#复制待解数组

#按行直接复制

#按列用要用zip合并转换

def tran_sodu(sodu,col=None):

if col==None:

return copy.deepcopy(soduku)

else:

new_sodu=list(zip(*copy.deepcopy(soduku)))

new_sodu=[list(i) for i in new_sodu]

return new_sodu

#填满空单元格,并为了格式统一好处理,把已知的值,由数值转为列表

def input_none(sodu):

for row in sodu:

row_none = [i for i in range(1,10) if i not in row]

for x in range(len(row)):

if row[x]=="":

row[x]=row_none

else:

row[x]=[row[x]]

return sodu

'''1.按小矩阵复制待解数组,9个小矩阵组成新数独2.用了numpy知识,很好用,但在单个元素的数据类型上有很多坑3.思路:把待解数组reshape成27组,每组3个元素的矩阵A,那么第一个小矩阵就取矩阵A的第1、4、7个元素,依次类推'''

def jvzheng(soduku):

arr = np.array(soduku)

# arr=[list(i) for i in arr.reshape(27,3)]

arr = arr.reshape(27,3).tolist()

for a in arr:

for b in range(3):

if a[b]!="":

a[b]=int(a[b])

newSodu=[[] for i in range(9)]

j=0

for i in range(9):

newSodu[i]=arr[j]+arr[j+3]+arr[j+6]

j=j+1

if j>=3 and j%3==0:

j=j+6

return newSodu

'''1、开始解数独后,遍历每个空单元格,去找该单元格对应到三个新数独的单元格时:(1)如果待解数独的单元格是soduku-cells(j,k),那么对应过去,按行的当然也是:按行-cells(j,k),按列的也很简单,相反,是:按列-cells(k,j)(2)按小矩阵的难解一点,就是下面的函数,和jvzheng()的主要代码一样,就是再转置一次,就转回去了,效果是:按小矩阵-cells(j,k)(3)按行-cells(j,k),按列-cells(k,j),按小矩阵-cells(j,k)这三个列表就能求交集了,最希望得到的是一个唯一值'''

def jvzheng2(soduku):

arr = np.array(soduku)

# arr=[list(i) for i in arr.reshape(27,3)]

arr=arr.reshape(27,3).tolist()

newSodu=[[] for i in range(9)]

j=0

for i in range(9):

newSodu[i]=arr[j]+arr[j+3]+arr[j+6]

j=j+1

if j>=3 and j%3==0:

j=j+6

return newSodu

import sys

sys.setrecursionlimit(50000) #这里设置大一些

'''1.递归函数,重复2.基本原理在jvzheng2()上面写了'''

def fin(s):

global cc,rr,jz,jz2

rr=input_none(tran_sodu(soduku)) # 按行填满各空格有可能的缺失值

cc=input_none(tran_sodu(soduku,1)) #按列

jz=input_none(jvzheng(soduku)) #按小矩阵

jz2=jvzheng2(jz)

'''规则一:行、列、小矩阵求交集遍历待解数独的每个空单元格,找到该单元格在rr,cc,jz2中的位置,并求交集当这个交集只有一个值时,就填入待解数独中'''

for j in range(9):

for k in range(9):

if s[j][k]=="":

'''下面的判断是numpy数据类型的一个坑,numpy会将[9]这样的单个数值的列表直接处理成数字9,这在算到最后一步时,代码就会跳错识了,因此加了判断,核心代码是else下面的那名就够了。'''

if isinstance(jz2[j][k],int):

target=set(rr[j][k])&set(cc[k][j])

else:

target=set(rr[j][k])&set(cc[k][j])&set(jz2[j][k])

if len(target)==1:

s[j][k]=list(target)[0]

'''规则二:如[8,4,[3,7,9],6,[1,5],[1,3,5],[1,5,9],[1,3,9],2]第三个[3,7,9],虽然有三个可能值,但观察一行,‘7’,在其他位置都没有出现过,因此第三位置肯定是‘7’'''

'''规则三……规则越多,能解的难题越多,达到通用,就不会出现“递归深度不够”,”栈溢出“等问题,数独知识有限,写不下去了,只能解简单数独。'''

#每递归一次,待解数独就会更新

#把待解数独摊开,如果没有一个空值,那说明解完了

if "" not in np.array(s).reshape(1,81)[0].tolist():

# if "" not in s[3]:

return s

else:

fin(s)

return s

def main():

fin(soduku)

print(soduku)

xw.Range("K1").value = soduku

if __name__ == '__main__':

main()

解出来了,因为例子实在太简单了,稍微复杂一点就出现“栈溢出”了。

因为规则只有一条,无论怎么递归都得不到答案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值