python解数独的思路_python穷举法解数独

总体思路 :

数独九行九列,一个list装一行,也就需要一个嵌套两层的list

初始会有很多数字,我可不想一个一个赋值

那就要想办法偷懒啦

然后再是穷举,如何科学的穷举

第一部分:录入

1287691-20180513220332025-2121564642.jpg

某在线数独网站的截图

要想办法,把它方便的变成嵌套的list

我的解决办法:

手打到Excel里面

1287691-20180513222039668-1469853003.jpg

然后另存为csv文件

1287691-20180513222254877-1535606921.jpg

然后就当做txt读取

l =None

with open('数独.csv','r',encoding = 'utf-8') as f:

l=f.readlines()print(l)'''运行结果

---------------------------------------

['\ufeff3,,,1,,8,4,,\n', ',,1,,,2,,3,\n', '4,,,,,,1,6,\n', ',5,8,,,9,,,4\n', ',3,,,5,,,,9\n', ',9,,3,,,5,,\n', ',,3,9,1,,,4,\n', '2,,7,5,,,9,,\n', '9,,,,4,,,5,3\n']'''

发现文本开头有个莫名其妙的\ufeff,另外它的长度是1

>>> s = '\ufeff3'

>>>len(s)2

只好加一句 l[0] = l[0][1:]

然后去掉末尾的\n 再以逗号为界切割

l =None

with open('数独.csv','r',encoding = 'utf-8') as f:

l=f.readlines()

l[0]= l[0][1:]

l= map(lambdai : i.rstrip(),l)

l= map(lambda i : i.split(","),l)for i inl:print(i,'---', len(i))'''运行结果

---------------------------------------

['3', '', '', '1', '', '8', '4', '', ''] --- 9

['', '', '1', '', '', '2', '', '3', ''] --- 9

['4', '', '', '', '', '', '1', '6', ''] --- 9

['', '5', '8', '', '', '9', '', '', '4'] --- 9

['', '3', '', '', '5', '', '', '', '9'] --- 9

['', '9', '', '3', '', '', '5', '', ''] --- 9

['', '', '3', '9', '1', '', '', '4', ''] --- 9

['2', '', '7', '5', '', '', '9', '', ''] --- 9

['9', '', '', '', '4', '', '', '5', '3'] --- 9'''

九行九列..完美

下一步全部处理成数字

鉴于int()无法将空字符串转化为0 所以需要新定义一个new_int

defnew_int(s):return int(s) if s else0

l=None

with open('数独.csv','r',encoding = 'utf-8') as f:

l=f.readlines()

l[0]= l[0][1:]

l= map(lambdai : i.rstrip(),l)

l= map(lambda i : i.split(","),l)

l= [ list(map(new_int, i)) for i inl]for i inl:print(i)'''运行结果

---------------------------------------

[3, 0, 0, 1, 0, 8, 4, 0, 0]

[0, 0, 1, 0, 0, 2, 0, 3, 0]

[4, 0, 0, 0, 0, 0, 1, 6, 0]

[0, 5, 8, 0, 0, 9, 0, 0, 4]

[0, 3, 0, 0, 5, 0, 0, 0, 9]

[0, 9, 0, 3, 0, 0, 5, 0, 0]

[0, 0, 3, 9, 1, 0, 0, 4, 0]

[2, 0, 7, 5, 0, 0, 9, 0, 0]

[9, 0, 0, 0, 4, 0, 0, 5, 3]'''

第二部分 穷举

假设81个格子有50是空的,每个格子1-9 9种可能

>>> 9**50

515377520732011331036461129765621272702107522001

显然不能傻乎乎的直接遍历

其实一个新格子并不是1-9 9种可能

它不可能是同行,同列,同区出现过的数字

这里将会用到set的加减

x,y = 0,1whole= {1,2,3,4,5,6,7,8,9}

x_set=set(l[x])#行

y_set = { l[i][y] for i in range(9) }#列

block_num =big_small[(x,y)]#查字典得到区号

block_set = { l[i][j] for i , j insmall_big[block_num] }#根据区号查该区的9个方格,然后根据位置构建set

possible = whole - x_set - y_set - block_set

下面补充下big_small和small_big两个字典

3x3的小区共9个 分别编号上0-8

0 | 1 | 2

3 | 4 | 5

6 | 7 | 8

原来在9x9的 x行y列 对应过去 就会在x//3行y//3列

对应编号就是x//3*3 + y//3

为了方便后面的使用,建立一个字典

big_small = { (x,y): (x//3)*3+(y//3) for x in range(9) for y in range(9)}'''---------------------------

>>> big_small[(5,5)]

4'''

这个字典是{位置:区号}

然后反着来一下

就可以根据 区号 查包含位置的字典(这才是重点)

big_small = { (x,y): (x//3)*3+(y//3) for x in range(9) for y in range(9)}

small_big= { x:[ ] for x in range(9)}for i , j inbig_small.items():

small_big[ j ].append(i)for i,j insmall_big.items():print(i,'-->',j)'''----------------------------------------------------

0 --> [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

1 --> [(0, 3), (0, 4), (0, 5), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)]

2 --> [(0, 6), (0, 7), (0, 8), (1, 6), (1, 7), (1, 8), (2, 6), (2, 7), (2, 8)]

3 --> [(3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (5, 0), (5, 1), (5, 2)]

4 --> [(3, 3), (3, 4), (3, 5), (4, 3), (4, 4), (4, 5), (5, 3), (5, 4), (5, 5)]

5 --> [(3, 6), (3, 7), (3, 8), (4, 6), (4, 7), (4, 8), (5, 6), (5, 7), (5, 8)]

6 --> [(6, 0), (6, 1), (6, 2), (7, 0), (7, 1), (7, 2), (8, 0), (8, 1), (8, 2)]

7 --> [(6, 3), (6, 4), (6, 5), (7, 3), (7, 4), (7, 5), (8, 3), (8, 4), (8, 5)]

8 --> [(6, 6), (6, 7), (6, 8), (7, 6), (7, 7), (7, 8), (8, 6), (8, 7), (8, 8)]'''

下面列下总体框架(???表示还没确定的细节)

#伪代码

l =???#读取文件获得未完成的数独

all_list =[l]#这个变量用于装 待处理的数独

key_list =[]#装正确的解

whileall_list:

one=all_list.pop()#从list末尾取出一个进行处理

x, y, ed =???(one)#这个函数找一个未填写的格子(值为0)

#x,y将接受格子的位置,

#ed接受一个逻辑值,以处理格子全被填满的特殊情况

ifed :

key_list.append(one)for i inone:print(i)#输出,保存解

continuepossible=???(x,y,one)#获取格子可能的数字

for i inpossible:

new_one=copy.deepcopy(one)#深度拷贝one

new_one[x][y] =i

all_list.append(new_one)#修改副本,并加入待处理list

只有一个函数不够清晰,

defoutput_cell(l):for i in range(9):for j in range(9):ifl[ i ][ j ] :pass

else:returni , j ,Falseelse:return None, None,True

全部的代码,

importcopydefnew_int(s):return int(s) if s else0defoutput_cell(l):for i in range(9):for j in range(9):ifl[ i ][ j ] :pass

else:returni , j ,Falseelse:returnNone, None,Truedefpossible_num(x,y,l):

whole= {1,2,3,4,5,6,7,8,9}

x_set=set(l[x])

y_set= { l[i][y] for i in range(9) }

block_num=big_small[(x,y)]

block_set= { l[i][j] for i , j insmall_big[block_num] }

possible= whole - x_set - y_set -block_setreturnpossible

big_small= { (x,y): (x//3)*3+(y//3) for x in range(9) for y in range(9)}

small_big= { x:[ ] for x in range(9)}for i , j inbig_small.items():

small_big[ j ].append(i)

l=None

with open('数独.csv','r',encoding = 'utf-8') as f:

l=f.readlines()

l[0]= l[0][1:]

l= map(lambdai : i.rstrip(),l)

l= map(lambda i : i.split(","),l)

l= [ list(map(new_int, i)) for i inl]

all_list=[l]

key_list=[]whileall_list:

one=all_list.pop()

x, y, ed=output_cell(one)ifed :

key_list.append(one)for i inone:print(i)continuepossible=possible_num(x,y,one)for i inpossible:

new_one=copy.deepcopy(one)

new_one[x][y]=i

all_list.append(new_one)else:print('遍历结束')print(len_num)

运行结果

'''---------------------------

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

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

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

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

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

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

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

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

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

#

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
是一种经典的数学逻辑游戏,常常用于测试人们的逻辑思维能力。而在matlab中,我们可以使用回溯解数。 回溯是一种穷举搜索的算,在解决数问题时非常有效。它通过在每个格子中填入数字,并检查其是否满足数游戏的规则。如果满足规则,则继续下一个格子;如果不满足规则,则回退到上一个位置重新选择数字,直到将整个数填满。 在matlab中,我们可以使用递归函数来实现回溯解数。首先,我们需要定义一个函数,该函数可以填写数格子的数字。接着,在该函数中,我们将每个空格子作为一个递归调用的起点,尝试填入数字,并检查是否满足数规则。如果填入的数字符合数规则,则递归调用函数,填写下一个空格子;如果不满足规则,则返回上一个格子,继续尝试其他数字。 当数填满时,我们就找到了一个解。如果数无解,则可以回退到上一个位置,继续尝试其他数字,直到找到解或者所有可能都尝试完。 通过回溯,我们可以解决各种难度的数问题。当然,在某些特定情况下,回溯可能需要较长的时间才能找到解。因此,对于更大的数或者更复杂的问题,我们可能需要考虑其他更高效的解决方。 总之,matlab中的回溯可以解决数问题。使用该方,我们可以通过递归函数,在每个格子中尝试填入数字,并检查是否满足数规则,从而找到数的解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值