仅利用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中zip()函数用法实例教程
Jul 31 Python
Python+Socket实现基于TCP协议的客户与服务端中文自动回复聊天功能示例
Aug 31 Python
python 读取txt,json和hdf5文件的实例
Jun 05 Python
pygame游戏之旅 添加游戏暂停功能
Nov 21 Python
深入理解Python异常处理的哲学
Feb 01 Python
python的debug实用工具 pdb详解
Jul 12 Python
浅谈pytorch卷积核大小的设置对全连接神经元的影响
Jan 10 Python
python语言实现贪吃蛇游戏
Nov 13 Python
细说NumPy数组的四种乘法的使用
Dec 18 Python
python文件路径操作方法总结
Dec 21 Python
TensorFlow2.0使用keras训练模型的实现
Feb 20 Python
Python制作春联的示例代码
Jan 22 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
欧美媒体选出10年前最流行的17部动画
2017/01/18 日漫
漫威DC即将合作联动,而双方早已经秘密开始
2020/04/09 欧美动漫
PHP容易被忽略而出错陷阱 数字与字符串比较
2011/11/10 PHP
php实现通用的从数据库表读取数据到数组的函数实例
2015/03/21 PHP
CodeIgniter连贯操作的底层原理分析
2016/05/17 PHP
header与缓冲区之间的深层次分析
2016/07/30 PHP
javascript检查日期格式的函数[比较全]
2008/10/17 Javascript
js实现按Ctrl+Enter发送效果
2014/09/18 Javascript
JavaScript 变量、作用域及内存
2015/04/08 Javascript
Javascript Event(事件)的传播与冒泡
2017/01/23 Javascript
js的OOP继承实现(必看篇)
2017/02/18 Javascript
JS奇技之利用scroll来监听resize详解
2017/06/15 Javascript
Angular 2父子组件数据传递之局部变量获取子组件其他成员
2017/07/04 Javascript
Vue keep-alive实践总结(推荐)
2017/08/31 Javascript
JS实现基本的网页计算器功能示例
2020/01/16 Javascript
js+canvas实现简单扫雷小游戏
2021/01/22 Javascript
[02:19]DOTA2上海特级锦标赛 观赛指南 Spectator Guide
2016/02/04 DOTA
python利用拉链法实现字典方法示例
2017/03/25 Python
Python图像处理之识别图像中的文字(实例讲解)
2018/05/10 Python
Python如何使用paramiko模块连接linux
2020/03/18 Python
关于Python解包知识点总结
2020/05/05 Python
使用HTML5做个画图板的方法介绍
2013/05/03 HTML / CSS
美国专业消费电子及摄影器材网站:B&H Photo Video
2019/12/18 全球购物
摩飞电器俄罗斯官方网站:Morphy Richards俄罗斯
2020/07/30 全球购物
亚马逊海外购:亚马逊美国、英国、日本、德国直邮
2021/03/18 全球购物
营销与策划应届生求职信
2013/11/04 职场文书
人事专员岗位职责
2013/11/20 职场文书
投标单位介绍信
2014/01/09 职场文书
学生会主席竞聘书
2014/03/31 职场文书
《花木兰》教学反思
2014/04/09 职场文书
锦旗标语大全
2014/06/23 职场文书
领导干部群众路线教育实践活动个人对照检查材料
2014/09/23 职场文书
2015年化验室工作总结
2015/04/23 职场文书
Python函数对象与闭包函数
2022/04/13 Python
python神经网络ResNet50模型
2022/05/06 Python
python标准库ElementTree处理xml
2022/05/20 Python