仅利用30行Python代码来展示X算法


Posted in Python onApril 01, 2015

假如你对数独解法感兴趣,你可能听说过精确覆盖问题。给定全集 X 和 X 的子集的集合 Y ,存在一个 Y 的子集 Y*,使得 Y* 构成 X 的一种分割。

这儿有个Python写的例子。
 

X = {1, 2, 3, 4, 5, 6, 7}
Y = {
  'A': [1, 4, 7],
  'B': [1, 4],
  'C': [4, 5, 7],
  'D': [3, 5, 6],
  'E': [2, 3, 6, 7],
  'F': [2, 7]}

这个例子的唯一解是['B', 'D', 'F']。

精确覆盖问题是NP完备(译注:指没有任何一个够快的方法可以在合理的时间内,意即多项式时间 找到答案)。X算法是由大牛高德纳发明并实现。他提出了一种高效的实现技术叫舞蹈链,使用双向链表来表示该问题的矩阵。

然而,舞蹈链实现起来可能相当繁琐,并且不易写地正确。接下来就是展示Python奇迹的时刻了!有天我决定用Python来编写X 算法,并且我想出了一个有趣的舞蹈链变种。
算法

主要的思路是使用字典来代替双向链表来表示矩阵。我们已经有了 Y。从它那我们能快速的访问每行的列元素。现在我们还需要生成行的反向表,换句话说就是能从列中快速访问行元素。为实现这个目的,我们把X转换为字典。在上述的例子中,它应该写为
 

X = {
  1: {'A', 'B'},
  2: {'E', 'F'},
  3: {'D', 'E'},
  4: {'A', 'B', 'C'},
  5: {'C', 'D'},
  6: {'D', 'E'},
  7: {'A', 'C', 'E', 'F'}}

眼尖的读者能注意到这跟Y的表示有轻微的不同。事实上,我们需要能快速删除和添加行到每列,这就是为什么我们使用集合。另一方面,高德纳没有提到这点,实际上整个算法中所有行是保持不变的。

以下是算法的代码。
 

def solve(X, Y, solution=[]):
  if not X:
    yield list(solution)
  else:
    c = min(X, key=lambda c: len(X[c]))
    for r in list(X[c]):
      solution.append(r)
      cols = select(X, Y, r)
      for s in solve(X, Y, solution):
        yield s
      deselect(X, Y, r, cols)
      solution.pop()
 
def select(X, Y, r):
  cols = []
  for j in Y[r]:
    for i in X[j]:
      for k in Y[i]:
        if k != j:
          X[k].remove(i)
    cols.append(X.pop(j))
  return cols
 
def deselect(X, Y, r, cols):
  for j in reversed(Y[r]):
    X[j] = cols.pop()
    for i in X[j]:
      for k in Y[i]:
        if k != j:
          X[k].add(i)

真的只有 30 行!
格式化输入

在解决实际问题前,我们需要将输入转换为上面描述的格式。可以这样简单处理

X = {j: set(filter(lambda i: j in Y[i], Y)) for j in X}

但这样太慢了。假如设 X 大小为 m,Y 的大小为 n,则迭代次数为 m*n。在这例子中的数独格子大小为 N,那需要 N^5 次。我们有更好的办法。
 

X = {j: set() for j in X}
for i in Y:
  for j in Y[i]:
    X[j].add(i)

这还是 O(m*n) 的复杂度,但是是最坏情况。平均情况下它的性能会好很多,因为它不需要遍历所有的空格位。在数独的例子中,矩阵中每行恰好有 4 个条目,无论大小,因此它有N^3的复杂度。
优点

  •     简单: 不需要构造复杂的数据结构,所有用到的结构Python都有提供。
  •     可读性: 上述第一个例子是直接从Wikipedia上的范例直接转录下来的!
  •     灵活性: 可以很简单得扩展来解决数独。

求解数独

我们需要做的就是把数独描述成精确覆盖问题。这里有完整的数独解法代码,它能处理任意大小,3×3,5×5,即使是2×3,所有代码少于100行,并包含doctest!(感谢Winfried Plappert 和 David Goodger的评论和建议)

Python 相关文章推荐
Python实现读取并保存文件的类
May 11 Python
浅谈python日志的配置文件路径问题
Apr 28 Python
Python加载带有注释的Json文件实例
May 23 Python
Tornado Web Server框架编写简易Python服务器
Jul 28 Python
linux下安装python3和对应的pip环境教程详解
Jul 01 Python
Python 离线工作环境搭建的方法步骤
Jul 29 Python
Django Channel实时推送与聊天的示例代码
Apr 30 Python
Python3-异步进程回调函数(callback())介绍
May 02 Python
记一次Django响应超慢的解决过程
Sep 17 Python
python 批量下载bilibili视频的gui程序
Nov 20 Python
python中xlutils库用法浅析
Dec 29 Python
总结几个非常实用的Python库
Jun 26 Python
探究数组排序提升Python程序的循环的运行效率的原因
Apr 01 #Python
用Python编写分析Python程序性能的工具的教程
Apr 01 #Python
对Python新手编程过程中如何规避一些常见问题的建议
Apr 01 #Python
利用Django框架中select_related和prefetch_related函数对数据库查询优化
Apr 01 #Python
用实例详解Python中的Django框架中prefetch_related()函数对数据库查询的优化
Apr 01 #Python
Python的Django框架中的select_related函数对QuerySet 查询的优化
Apr 01 #Python
简单的Python2.7编程初学经验总结
Apr 01 #Python
You might like
php使用curl获取header检测开启GZip压缩的方法
2018/08/15 PHP
PHP使用gearman进行异步的邮件或短信发送操作详解
2020/02/27 PHP
Jquery Validation插件防止重复提交表单的解决方法
2010/03/05 Javascript
jQuery选择器简明总结(含用法实例,一目了然)
2014/04/25 Javascript
使用jsonp完美解决跨域问题
2014/11/27 Javascript
chrome不支持form.submit的解决方案
2015/04/28 Javascript
js限制input标签中只能输入中文
2015/06/26 Javascript
sso跨域写cookie的一段js脚本(推荐)
2016/05/25 Javascript
Javascript数组中push方法用法分析
2016/10/31 Javascript
AngularJS 霸道的过滤器小结
2017/04/26 Javascript
一次围绕setTimeout的前端面试经验分享
2017/06/15 Javascript
Vue学习笔记进阶篇之vue-router安装及使用方法
2017/07/19 Javascript
JS如何实现在页面上快速定位(锚点跳转问题)
2017/08/14 Javascript
jquery实现图片跟随鼠标的实例
2017/10/17 jQuery
Vue监听数据渲染DOM完以后执行某个函数详解
2018/09/11 Javascript
vue-cli安装使用流程步骤详解
2018/11/08 Javascript
如何在Node和浏览器控制台中打印彩色文字
2020/01/09 Javascript
weui上传多图片,压缩,base64编码的示例代码
2020/06/22 Javascript
关于vue 项目中浏览器跨域的配置问题
2020/11/10 Javascript
Vuex实现简单购物车
2021/01/10 Vue.js
多线程爬虫批量下载pcgame图片url 保存为xml的实现代码
2013/01/17 Python
python获取指定目录下所有文件名列表的方法
2015/05/20 Python
python实现二分查找算法
2017/09/21 Python
对python:循环定义多个变量的实例详解
2019/01/20 Python
Python里字典的基本用法(包括嵌套字典)
2019/02/27 Python
在win10和linux上分别安装Python虚拟环境的方法步骤
2019/05/09 Python
python3.5 cv2 获取视频特定帧生成jpg图片
2019/08/28 Python
Python 程序员必须掌握的日志记录
2020/08/17 Python
英国护肤品购物网站:Beauty Expert
2016/08/19 全球购物
意大利珠宝店:Luxury Zone
2019/01/05 全球购物
农业资源与环境专业自荐信范文
2013/12/30 职场文书
工作分析计划书
2014/04/30 职场文书
客运企业隐患排查工作方案
2014/06/06 职场文书
计算机系统管理员求职信
2014/06/20 职场文书
优秀党员学习焦裕禄精神思想汇报范文
2014/09/10 职场文书
小学班主任自我评价
2015/03/11 职场文书