仅利用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 03 Python
python字符串连接方式汇总
Aug 21 Python
以Python的Pyspider为例剖析搜索引擎的网络爬虫实现方法
Mar 30 Python
qpython3 读取安卓lastpass Cookies
Jun 19 Python
Python中%r和%s的详解及区别
Mar 16 Python
解决python3 urllib中urlopen报错的问题
Mar 25 Python
对python字典过滤条件的实例详解
Jan 22 Python
python程序控制NAO机器人行走
Apr 29 Python
PyTorch之图像和Tensor填充的实例
Aug 18 Python
解决os.path.isdir() 判断文件夹却返回false的问题
Nov 29 Python
Django 用户认证Auth组件的使用
Nov 30 Python
python读写数据读写csv文件(pandas用法)
Dec 14 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
全国FM电台频率大全 - 19 广东省
2020/03/11 无线电
php检测用户是否用手机(Mobile)访问网站的类
2014/01/09 PHP
ThinkPHP连接数据库及主从数据库的设置教程
2014/08/22 PHP
php实现三级级联下拉框
2016/04/17 PHP
用PHP做了一个领取优惠券活动的示例代码
2019/07/05 PHP
JavaScript 对象链式操作测试代码
2010/04/25 Javascript
使用jQuery全局事件ajaxStart为特定请求实现提示效果的代码
2010/12/30 Javascript
javascript date格式化示例
2013/09/25 Javascript
jQuery读取和设定KindEditor值的方法
2013/11/22 Javascript
jquery mobile动态添加元素之后不能正确渲染解决方法说明
2014/03/05 Javascript
将HTML的左右尖括号等转义成实体形式的两种实现方式
2014/05/04 Javascript
javascript中加号(+)操作符的一些神奇作用
2014/06/06 Javascript
深入理解JavaScript系列(38):设计模式之职责链模式详解
2015/03/04 Javascript
avalon js实现仿微博拖动图片排序
2015/08/14 Javascript
微信小程序 引入es6 promise
2017/04/12 Javascript
Swiper实现轮播图效果
2017/07/03 Javascript
利用node.js如何创建子进程详解
2017/12/09 Javascript
利用vue开发一个所谓的数独方法实例
2017/12/21 Javascript
Vue props用法详解(小结)
2018/07/03 Javascript
Vue.js 使用v-cloak后仍显示变量的解决方法
2018/11/19 Javascript
JavaScript中将值转换为字符串的五种方法总结
2019/06/06 Javascript
ElementUI中el-tree节点的操作的实现
2020/02/27 Javascript
JS使用for in有序获取对象数据
2020/05/19 Javascript
在vue中实现禁止屏幕滚动,禁止屏幕滑动
2020/07/22 Javascript
解决vue项目运行npm run serve报错的问题
2020/10/26 Javascript
python操作xml文件详细介绍
2014/06/09 Python
介绍Python中几个常用的类方法
2015/04/08 Python
python实现将内容分行输出
2015/11/05 Python
Python中struct模块对字节流/二进制流的操作教程
2017/01/21 Python
Python实现将json文件中向量写入Excel的方法
2018/03/26 Python
详解python解压压缩包的五种方法
2019/07/05 Python
pycharm新建Vue项目的方法步骤(图文)
2020/03/04 Python
Marlies Dekkers内衣荷兰官方网店:荷兰奢侈内衣品牌
2020/03/27 全球购物
四下基层实施方案
2014/03/28 职场文书
数学备课组工作总结
2015/08/12 职场文书
Python 制作自动化翻译工具
2021/04/25 Python