如何用python计算数独_用python解决数独
看到了,季以安:用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()
解出來了,因為例子實在太簡單了,稍微復雜一點就出現“棧溢出”了。
因為規則只有一條,無論怎么遞歸都得不到答案。
總結
以上是生活随笔為你收集整理的如何用python计算数独_用python解决数独的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python实现组合问题_python3
- 下一篇: python向dict里添加_Pytho