仅利用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调用短信猫控件实现发短信功能实例
Jul 04 Python
寻找网站后台地址的python脚本
Sep 01 Python
零基础写python爬虫之HTTP异常处理
Nov 05 Python
在Python中操作字典之fromkeys()方法的使用
May 21 Python
pandas object格式转float64格式的方法
Apr 10 Python
Django框架HttpResponse对象用法实例分析
Nov 01 Python
python动态文本进度条的实例代码
Jan 22 Python
Python实现列表中非负数保留,负数转化为指定的数值方式
Jun 04 Python
Keras 利用sklearn的ROC-AUC建立评价函数详解
Jun 15 Python
解决Keras的自定义lambda层去reshape张量时model保存出错问题
Jul 01 Python
python 实现端口扫描工具
Dec 18 Python
Pytorch自定义Dataset和DataLoader去除不存在和空数据的操作
Mar 03 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 一个页面执行时间类代码
2010/03/05 PHP
PHP读取数据库并按照中文名称进行排序实现代码
2013/01/29 PHP
用PHP和Shell写Hadoop的MapReduce程序
2014/04/15 PHP
PHP生成网站桌面快捷方式代码分享
2014/10/11 PHP
PHP PDOStatement::columnCount讲解
2019/01/30 PHP
JavaScript入门教程(6) Window窗口对象
2009/01/31 Javascript
javascript中日期转换成时间戳的小例子
2013/03/21 Javascript
JavaScript实现两个Table固定表头根据页面大小自行调整
2014/01/03 Javascript
jquery解析xml字符串简单示例
2014/04/11 Javascript
创建你的第一个AngularJS应用的方法
2015/06/16 Javascript
js实现TAB切换对应不同颜色的代码
2015/08/31 Javascript
逐一介绍Jquery data()、Jquery stop()、jquery delay()函数(详)
2015/11/04 Javascript
jquery在ie7下选择器的问题导致append失效的解决方法
2016/01/10 Javascript
jQuery Ajax 异步加载显示等待效果代码分享
2016/08/01 Javascript
websocket+node.js实现实时聊天系统问题咨询
2017/05/17 Javascript
vue v-on监听事件详解
2017/05/17 Javascript
JS简单实现滑动加载数据的方法示例
2017/10/18 Javascript
vue cli使用绝对路径引用图片问题的解决
2017/12/06 Javascript
js将当前时间格式化为 年-月-日 时:分:秒的实现代码
2018/01/20 Javascript
vue路由守卫及路由守卫无限循环问题详析
2019/09/05 Javascript
在Vue中使用Echarts实例图的方法实例
2020/10/10 Javascript
Python解析json之ValueError: Expecting property name enclosed in double quotes: line 1 column 2(char 1)
2017/07/06 Python
django 环境变量配置过程详解
2019/08/06 Python
Python如何定义有可选参数的元类
2020/07/31 Python
vscode+PyQt5安装详解步骤
2020/08/12 Python
什么是CSS3 HSLA色彩模式?HSLA模拟渐变色条
2016/04/26 HTML / CSS
html5 外链式实现加减乘除的代码
2019/09/04 HTML / CSS
中国电子产品外贸网站:MiniIntheBox
2017/02/06 全球购物
英国奢侈品概念店:Base Blu
2019/05/16 全球购物
初中语文教学反思
2014/02/02 职场文书
教师学习培训邀请函
2014/02/04 职场文书
人力资源主管的岗位职责
2014/03/15 职场文书
教师求职信范文
2014/05/24 职场文书
创先争优个人承诺书
2014/08/30 职场文书
初三数学教学反思
2016/02/17 职场文书
解决Pytorch修改预训练模型时遇到key不匹配的情况
2021/06/05 Python