仅利用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 05 Python
Windows和Linux下使用Python访问SqlServer的方法介绍
Mar 10 Python
python通过wxPython打开一个音频文件并播放的方法
Mar 25 Python
python and or用法详解
Jun 26 Python
python爬虫解决验证码的思路及示例
Aug 01 Python
wxPython实现绘图小例子
Nov 19 Python
python实现双色球随机选号
Jan 01 Python
OpenCV中VideoCapture类的使用详解
Feb 14 Python
Python loguru日志库之高效输出控制台日志和日志记录
Mar 07 Python
python中pathlib模块的基本用法与总结
Aug 17 Python
如何用python插入独创性声明
Mar 31 Python
python 如何用terminal输入参数
May 25 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计算数组不为空元素个数的方法
2014/01/27 PHP
php图片处理函数获取类型及扩展名实例
2014/11/19 PHP
PHP+MySQL存储数据常见中文乱码问题小结
2016/06/13 PHP
php使用Jpgraph创建3D饼形图效果示例
2017/02/15 PHP
Yii框架日志记录Logging操作示例
2018/07/12 PHP
PHP设计模式入门之迭代器模式原理与实现方法分析
2020/04/26 PHP
关于Anemometer图形化显示MySQL慢日志的工具搭建及使用的详细介绍
2020/07/13 PHP
dropdownlist之间的互相联动实现(显示与隐藏)
2009/11/24 Javascript
JavaScript中函数(Function)的apply与call理解
2015/07/08 Javascript
JavaScript实现删除,移动和复制文件的方法
2015/08/05 Javascript
详解AngularJS中ng-src指令的使用
2016/09/07 Javascript
BootStrap轮播HTML代码(推荐)
2016/12/10 Javascript
微信小程序 HTTPS报错整理常见问题及解决方案
2016/12/14 Javascript
深入理解Javascript箭头函数中的this
2017/02/13 Javascript
vscode 插件开发 + vue的操作方法
2020/06/05 Javascript
Python进行数据科学工作的简单入门教程
2015/04/01 Python
Python爬取国外天气预报网站的方法
2015/07/10 Python
基于Python log 的正确打开方式
2018/04/28 Python
python os模块简单应用示例
2019/05/23 Python
python3.6中@property装饰器的使用方法示例
2019/08/17 Python
Python中list循环遍历删除数据的正确方法
2019/09/02 Python
Pytorch中Tensor与各种图像格式的相互转化详解
2019/12/26 Python
python 6.7 编写printTable()函数表格打印(完整代码)
2020/03/25 Python
Matplotlib 折线图plot()所有用法详解
2020/07/28 Python
python/golang 删除链表中的元素
2020/09/14 Python
Priority Pass机场贵宾室会籍计划:全球超过1200间机场贵宾室
2018/08/26 全球购物
C,C++的几个面试题小集
2013/07/13 面试题
历史学专业大学生找工作的自我评价
2013/10/16 职场文书
生日主持词
2014/03/20 职场文书
好习惯伴我成长演讲稿
2014/05/21 职场文书
婚内房产协议书范本
2014/10/02 职场文书
市委常委会班子党的群众路线教育实践活动整改方案
2014/10/25 职场文书
小学生勤俭节约倡议书
2015/04/29 职场文书
2019年中,最受大众欢迎的6本新书
2019/08/07 职场文书
2019年作为一名实习生的述职报告
2019/09/29 职场文书
Python pyecharts案例超市4年数据可视化分析
2022/08/14 Python