栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Python中最短的数独求解器

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python中最短的数独求解器

好了,您可以通过修复语法来使事情变得容易一些:

def r(a):  i = a.find('0')  ~i or exit(a)  [m in[(i-j)%9*(i/9^j/9)*(i/27^j/27|i%9/3^j%9/3)or a[j]for j in range(81)] or r(a[:i]+m+a[i+1:])for m in'%d'%5**18]from sys import *r(argv[1])

清理一点:

from sys import exit, argvdef r(a):  i = a.find('0')  if i == -1:    exit(a)  for m in '%d' % 5**18:    m in[(i-j)%9*(i/9^j/9)*(i/27^j/27|i%9/3^j%9/3) or a[j] for j in range(81)] or r(a[:i]+m+a[i+1:])r(argv[1])

好的,因此此脚本需要一个命令行参数,并在其上调用函数r。如果该字符串中没有零,则r退出并输出其参数。

(如果传递了另一种类型的对象,则None等于传递零,并且将任何其他对象打印到sys.stderr并导致退出代码为1。特别是sys.exit(“ some
error message”)是一个发生错误时退出程序的快速方法。请参见
http://www.python.org/doc/2.5.2/lib/module-
sys.html)

我猜这意味着零对应于开放空间,并且解决了没有零的难题。然后就是讨厌的递归表达式。

循环很有趣:

for m in'%d'%5**18

为什么是5 **
18?原来,结果

'%d'%5**18
'3814697265625'
。这是一个字符串,每个数字至少有1-9个字符,因此它可能试图放置每个数字。实际上,这似乎
r(a[:i]+m+a[i+1:])
是在做的事情:递归调用r,第一个空格由该字符串中的一个数字填充。但这仅在较早的表达式为false时才会发生。让我们看一下:

m in [(i-j)%9*(i/9^j/9)*(i/27^j/27|i%9/3^j%9/3) or a[j] for j in range(81)]

因此,仅当m不在该怪物列表中时,才进行放置。每个元素可以是一个数字(如果第一个表达式为非零)或一个字符(如果第一个表达式为零)。如果m作为字符出现,则m被排除为可能的替换,只有在第一个表达式为零时才可能发生。表达式何时为零?

它有三部分相乘:

  • (i-j)%9
    如果i和j相隔9的倍数,即同一列,则为零。
  • (i/9^j/9)
    如果i / 9 == j / 9,则为零,即同一行。
  • (i/27^j/27|i%9/3^j%9/3)
    如果两个都为零,则为零:
    • i/27^j^27
      如果i / 27 == j / 27,则为零,即相同的三行块
    • i%9/3^j%9/3
      如果i%9/3 == j%9/3,则为零,即同一列的三列

如果这三个部分中的任何一个为零,则整个表达式为零。换句话说,如果i和j共享行,列或3x3块,则j的值不能用作i处空白的候选对象。啊哈!

from sys import exit, argvdef r(a):  i = a.find('0')  if i == -1:    exit(a)  for m in '3814697265625':    okay = True    for j in range(81):      if (i-j)%9 == 0 or (i/9 == j/9) or (i/27 == j/27 and i%9/3 == j%9/3):        if a[j] == m:          okay = False          break    if okay:      # At this point, m is not excluded by any row, column, or block, so let's place it and recurse      r(a[:i]+m+a[i+1:])r(argv[1])

请注意,如果没有一个放置成功,r将返回并返回到可以选择其他位置的位置,因此这是基本的深度优先算法。

不使用任何启发式方法,效率不是特别高。我从Wikipedia(http://en.wikipedia.org/wiki/Sudoku)看了这个难题:

$ time python sudoku.py 530070000600195000098000060800060003400803001700020006060000280000419005000080079534678912672195348198342567859761423426853791713924856961537284287419635345286179real    0m47.881suser    0m47.223ssys 0m0.137s

附录:我如何将其重写为维护程序员(此版本的速度提高了93倍:)

import sysdef same_row(i,j): return (i/9 == j/9)def same_col(i,j): return (i-j) % 9 == 0def same_block(i,j): return (i/27 == j/27 and i%9/3 == j%9/3)def r(a):  i = a.find('0')  if i == -1:    sys.exit(a)  excluded_numbers = set()  for j in range(81):    if same_row(i,j) or same_col(i,j) or same_block(i,j):      excluded_numbers.add(a[j])  for m in '123456789':    if m not in excluded_numbers:      # At this point, m is not excluded by any row, column, or block, so let's place it and recurse      r(a[:i]+m+a[i+1:])if __name__ == '__main__':  if len(sys.argv) == 2 and len(sys.argv[1]) == 81:    r(sys.argv[1])  else:    print 'Usage: python sudoku.py puzzle'    print '  where puzzle is an 81 character string representing the puzzle read left-to-right, top-to-bottom, and 0 is a blank'


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/383508.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号