python穷举法解数独
总体思路 :
数独九行九列,一个list装一行,也就需要一个嵌套两层的list
初始会有很多数字,我可不想一个一个赋值
那就要想办法偷懒啦
然后再是穷举,如何科学的穷举
第一部分:录入

某在线数独网站的截图
要想办法,把它方便的变成嵌套的list
我的解决办法:
手打到Excel里面

然后另存为csv文件

然后就当做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(lambda i : i.rstrip(),l)
l = map(lambda i : i.split(","),l) for i in l:
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
def new_int(s):
return int(s) if s else 0 l = None
with open('数独.csv','r',encoding = 'utf-8') as f:
l = f.readlines()
l[0] = l[0][1:]
l = map(lambda i : i.rstrip(),l)
l = map(lambda i : i.split(","),l)
l = [ list(map(new_int, i)) for i in l] for i in l:
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,1
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 in small_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 in big_small.items():
small_big[ j ].append(i)
for i,j in small_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 = []
#装正确的解 while all_list:
one = all_list.pop()
#从list末尾取出一个进行处理
x, y, ed = ???(one)
#这个函数找一个未填写的格子(值为0)
#x,y将接受格子的位置,
#ed接受一个逻辑值,以处理格子全被填满的特殊情况
if ed :
key_list.append(one)
for i in one:
print(i)
#输出,保存解
continue
possible = ???(x,y,one)
#获取格子可能的数字
for i in possible:
new_one = copy.deepcopy(one)
#深度拷贝one
new_one[x][y] = i
all_list.append(new_one)
#修改副本,并加入待处理list
只有一个函数不够清晰,
def output_cell(l):
for i in range(9):
for j in range(9):
if l[ i ][ j ] :
pass
else:
return i , j ,False
else:
return None, None,True
全部的代码,
import copy def new_int(s):
return int(s) if s else 0 def output_cell(l):
for i in range(9):
for j in range(9):
if l[ i ][ j ] :
pass
else:
return i , j ,False
else:
return None, None,True def possible_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 in small_big[block_num] }
possible = whole - x_set - y_set - block_set
return possible 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 in big_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(lambda i : i.rstrip(),l)
l = map(lambda i : i.split(","),l)
l = [ list(map(new_int, i)) for i in l] all_list = [l]
key_list = [] while all_list:
one = all_list.pop()
x, y, ed = output_cell(one)
if ed :
key_list.append(one)
for i in one:
print(i)
continue
possible = possible_num(x,y,one)
for i in possible:
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]
'''
#
python穷举法解数独的更多相关文章
- python 穷举法 算24点(史上最简短代码)
本来想用回溯法实现 算24点.题目都拟好了,就是<python 回溯法 子集树模板 系列 -- 7.24点>.无奈想了一天,没有头绪.只好改用暴力穷举法. 思路说明 根据四个数,三个运算符 ...
- 穷举法、for循环、函数、作用域、斐波那契数
1.穷举法 枚举所有可能性,直到得到正确的答案或者尝试完所有值. 穷举法经常是解决问题的最实用的方法,它实现起来热别容易,并且易于理解. 2.for循环 for语句一般形式如下: for variab ...
- 通过穷举法快速破解excel或word加密文档最高15位密码
1.打开文件 2.工具 --- 宏 ---- 录制新宏 --- 输入名字如 :aa 3.停止录制 ( 这样得到一个空宏 ) 4.工具 --- 宏 ---- 宏 , 选 aa, 点编辑按钮 5.删除窗口 ...
- for循环语句以及迭代法和穷举法
循环语句: 四要素:初始条件,循环条件,状态改变,循环体 for(初始条件;循环条件;状态改变){ //循环体} 案例1:打印等腰直角三角形和菱形 左上三角 static void Main(stri ...
- C#4 for循环 迭代法 穷举法应用
for()循环. 四要素: 初始条件,循环条件,状态改变,循环体. 执行过程: 初始条件--循环条件--循环体--状态改变--循环条件.... 注意:for的小括号里面分号隔开,for的小括号后不要加 ...
- C# for 循环 迭代法 穷举法
for()循环. 四要素: 初始条件,循环条件,状态改变,循环体. 执行过程: 初始条件--循环条件--循环体--状态改变--循环条件.... 注意:for的小括号里面分号隔开,for的小括号后不要加 ...
- 【2-24】for循环嵌套,跳转语句,异常语句,穷举法、迭代法
For循环嵌套与if嵌套相似,是在for中再套for,其结构如下: For(;;) { For(;;){} }经典题型为打印星星例: Console.Write("请输入一个奇数:" ...
- C# 异常语句 跳转语句 while循环 穷举法 迭代法
一 异常语句 ♦ try.....catch....finally 结构形式 try{ 可能会出错的代码语句 如果这里出错了,那么不会在继续下面的代码,而是直接进入catch中处理异常}catc ...
- 基本算法思想之穷举法(C++语言描述)
穷举算法(Exhaustive Attack method)是最简单的一种算法,其依赖于计算机的强大计算能力来穷尽每一种可能性,从而达到求解问题的目的.穷举算法效率不高,但是适应于一些没有规律可循的场 ...
随机推荐
- 帆软报表(finereport)间格运算常用公式
1.1在C3(占比)单元格中直接使用占比公式:=PROPORTION(B3):占比:当前值占总值的比例 1.2 计组内占比注:C2[!0]{A2=$A2},表示C2扩展出来地区相同的单元格.sum(C ...
- 洛谷 P1111 修复公路
题目链接 https://www.luogu.org/problemnew/show/P1111 以后只发题目链接!!! 题目大意 给出A地区的村庄数N,和公路数M,公路是双向的.并告诉你每条公路的连 ...
- CentOS7像外部163邮箱发送邮件
我们在运维过程中,为了随时了解服务器的工作状态,出现问题随时提醒,像个人邮箱发送邮件是必须的,但是刚刚安装好的系统是无法发送邮件的.需要们进行一些配置和程序的安装,我安装完系统后,自带mail12.5 ...
- Django学习(一)
Django 是python开发的一个免费开源的Web框架,可以用于快速搭建高性能,优雅的网站.(emmmm,百度百科).本学期需要做python数据的可视化,之前搞过两次SMM和SSH,但是之后ja ...
- TP-Shop安装步骤教程(Windows版)
TP-Shop安装步骤教程(Windows版) PS:首次发文,请多指教! 一.安装要求 1.PHP5.4以上,MYsql5.5以上. 2.需要Phpcurl,gd库.php_mysqli,php_o ...
- selenium笔记(1)
selenium笔记(1) 一.关闭页面:1.driver.close() 关闭当前页面2.driver.quit() 退出整个浏览器 二.定位元素:1.find_element_by_id: 根据i ...
- Linux中jdk的安装配置
1.下载jdk安装包 2.解压文件:tar -zxvf jdk-8u211-linux-x64.tar.gz 3.编辑环境变量:vi /etc/profile 4.在环境变量文末添加三行: expor ...
- B站资源索引
自从搭建了B站的监控之后,就收集了一堆up主,下面分类整理一下,排名不分先后,内容会持续更新……2019-4-10 19:04:08 一.酷玩&装机&开箱 1.AS极客 2.Virtu ...
- iOS异常捕获和处理
2013年4月份整理的代码,仅作记录: //先宏定义 //发布和未发布状态的日志切换 #ifdef DEBUG //异常栈开关 #define STACK_KEY YES ...
- python之lambda函数
今天复习python,看见一个关于lambda函数的例子,在python中使用lambda在某些时候十分方便,因为不必为了实现某些简单功能而新建一个函数.但是有这么一个lambda实例令我有些疑惑,现 ...