仅利用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 相关文章推荐
利用Anaconda完美解决Python 2与python 3的共存问题
May 25 Python
Python爬虫之xlml解析库(全面了解)
Aug 08 Python
详解K-means算法在Python中的实现
Dec 05 Python
使用python爬虫获取黄金价格的核心代码
Jun 13 Python
Python 字符串与数字输出方法
Jul 16 Python
tensorflow更改变量的值实例
Jul 30 Python
Python 单元测试(unittest)的使用小结
Nov 14 Python
使用Rasterio读取栅格数据的实例讲解
Nov 26 Python
python pprint模块中print()和pprint()两者的区别
Feb 10 Python
jupyter lab的目录调整及设置默认浏览器为chrome的方法
Apr 10 Python
Python txt文件如何转换成字典
Nov 03 Python
python操作xlsx格式文件并读取
Jun 02 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面向对象全攻略 (十五) 多态的应用
2009/09/30 PHP
PHP使用DOMDocument类生成HTML实例(包含常见标签元素)
2014/06/25 PHP
PHP代码实现表单数据验证类
2015/07/28 PHP
PHP6新特性分析
2016/03/03 PHP
jquery的ajaxSubmit()异步上传图片并保存表单数据演示代码
2013/06/04 Javascript
图标线性回归斜着移动到指定的位置
2013/08/16 Javascript
jquery基础教程之数组使用详解
2014/03/10 Javascript
JavaScript编程中容易出BUG的几点小知识
2015/01/31 Javascript
Jquery中$.post和$.ajax的用法小结
2015/04/28 Javascript
JS实现当前页居中分页效果的方法
2015/06/18 Javascript
jquery实现图片放大镜功能
2015/11/23 Javascript
Webpack 实现 AngularJS 的延迟加载
2016/03/02 Javascript
浅谈js数组和splice的用法
2016/12/04 Javascript
Jquery Easyui进度条组件Progress使用详解(8)
2020/03/26 Javascript
Bootstrap页面标题Page Header的实现方法
2017/03/22 Javascript
ReactJs设置css样式的方法
2017/06/08 Javascript
js实现导航跟随效果
2018/11/17 Javascript
微信小程序实现图片滚动效果示例
2018/12/05 Javascript
js实现的格式化数字和金额功能简单示例
2019/07/30 Javascript
浅析webpack-bundle-analyzer在vue-cli3中的使用
2019/10/23 Javascript
使用Python开发windows GUI程序入门实例
2014/10/23 Python
Java编程迭代地删除文件夹及其下的所有文件实例
2018/02/10 Python
Python单向链表和双向链表原理与用法实例详解
2018/08/31 Python
python 实现语音聊天机器人的示例代码
2018/12/02 Python
Kali Linux安装ipython2 和 ipython3的方法
2019/07/11 Python
Numpy将二维数组添加到空数组的实现
2019/12/05 Python
生产副总岗位职责
2013/11/28 职场文书
药学专业个人的自我评价
2013/12/31 职场文书
《走一步再走一步》教学反思
2014/02/15 职场文书
文秘应聘自荐书范文
2014/02/18 职场文书
安全责任书范文
2014/08/25 职场文书
工作骂脏话检讨书
2014/10/05 职场文书
党的群众路线教育实践活动个人整改方案
2014/10/25 职场文书
开除员工通知
2015/04/22 职场文书
2019企业文化管理制度范本!
2019/08/06 职场文书
python数字图像处理数据类型及颜色空间转换
2022/06/28 Python