仅利用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入门篇之正则表达式
Oct 20 Python
python统计一个文本中重复行数的方法
Nov 19 Python
Python遍历指定文件及文件夹的方法
May 09 Python
python比较2个xml内容的方法
May 11 Python
Python的Django框架中URLconf相关的一些技巧整理
Jul 18 Python
Python使用matplotlib填充图形指定区域代码示例
Jan 16 Python
python 数据生成excel导出(xlwt,wlsxwrite)代码实例
Aug 23 Python
Python的Lambda函数用法详解
Sep 03 Python
tensorflow生成多个tfrecord文件实例
Feb 17 Python
Django更新models数据库结构步骤
Apr 01 Python
python Canny边缘检测算法的实现
Apr 24 Python
Python移位密码、仿射变换解密实例代码
Jun 27 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获取淘宝分类id示例
2014/01/16 PHP
destoon实现调用当前栏目分类及子分类和三级分类的方法
2014/08/21 PHP
PHP SplObjectStorage使用实例
2015/05/12 PHP
PHP面向对象中new self()与 new static()的区别浅析
2017/08/17 PHP
学习ExtJS Panel常用方法
2009/10/07 Javascript
jQuery Jcrop插件实现图片选取功能
2011/11/23 Javascript
js实现鼠标拖动图片并兼容IE/FF火狐/谷歌等主流浏览器
2013/06/06 Javascript
JS获取iframe中marginHeight和marginWidth属性的方法
2015/04/01 Javascript
JS实现可直接显示网页代码运行效果的HTML代码预览功能实例
2015/08/06 Javascript
jQuery实现下拉框左右移动(全部移动,已选移动)
2016/04/15 Javascript
JSON 的正确用法探讨:Pyhong、MongoDB、JavaScript与Ajax
2016/05/15 Javascript
jQuery Ajax和getJSON获取后台普通json数据和层级json数据用法分析
2016/06/08 Javascript
纯JS实现轮播图
2017/02/22 Javascript
浅谈Angular路由守卫
2017/08/26 Javascript
react router4+redux实现路由权限控制的方法
2018/05/03 Javascript
vue组件横向树实现代码
2018/08/02 Javascript
从vue源码解析Vue.set()和this.$set()
2018/08/30 Javascript
Angular CLI 使用教程指南参考小结
2019/04/10 Javascript
JS为什么说async/await是generator的语法糖详解
2019/07/11 Javascript
js判断复选框是否选中的方法示例【基于jQuery】
2019/10/10 jQuery
使用Python编写Prometheus监控的方法
2018/10/15 Python
Python中BeautifuSoup库的用法使用详解
2019/11/15 Python
python3.7通过thrift操作hbase的示例代码
2020/01/14 Python
python 自定义异常和主动抛出异常(raise)的操作
2020/12/11 Python
Artist Guitars新西兰:乐器在线商店
2017/09/17 全球购物
销售会计工作职责
2013/12/02 职场文书
员工工作表扬信范文
2014/01/13 职场文书
儿媳婚宴答谢词
2014/01/14 职场文书
浙江文明网签名寄语
2014/01/18 职场文书
学生感冒英文请假条
2014/02/04 职场文书
2014年学校教学工作总结
2014/12/06 职场文书
穆斯林的葬礼读书笔记
2015/06/26 职场文书
小学作文指导之如何写人?
2019/07/08 职场文书
python - asyncio异步编程
2021/04/06 Python
Python matplotlib可视化之绘制韦恩图
2022/02/24 Python
Python加密技术之RSA加密解密的实现
2022/04/08 Python