本帖最后由 yxp 于 2018-3-30 00:02 编辑
最近经常开会无聊的时候就玩玩数独,顺手查了一下数独的相关知识。
终盘数量:
数独中的数字排列千变万化,那么究竟有多少种终盘的数字组合呢?
答案是6,670,903,752,021,072,936,960(约为6.67×10的21次方)种组合,2005年由Bertram Felgenhauer和Frazer Jarvis计算出该数字,并将计算方法发布在他们网站上,如果将等价终盘(如旋转、翻转、行行对换,数字对换等变形)不计算,则有5,472,730,538个组合。数独终盘的组合数量都如此惊人,那么数独题目数量就更加不计其数了,因为每个数独终盘又可以根据提示数的多寡,制作出无数道合格的数独题目。
标准数独:
目前(截止2011年)发现的最少提示数9×9标准数独为17个提示数,截止2011年11月24日16:14,共发现了非等价17提示数谜题49151题,此数量仍在缓慢上升中,如果你先发现了17提示数的题目,可以上传至“17格数独验证”网站,当然你也可以在这里下载这49151题。
Gary McGuire的团队在2009年设计了新的算法,利用Deadly Pattern的思路,花费710万小时CPU时间后,于2012年1月1日提出了9×9标准数独不存在16提示唯一解的证明,继而说明最少需要17个提示数。并将他们的论文以及源代码更新在2009年的页面上。
看见e派用了自定义函数,用标准lisp函数也不是很麻烦,关键是求解数独的算法。
- ;; sudoku-str->row 字符串转行表,传入参数 str
- ;;(setq str "000000980020010000004057010000000506019060340203000000080420100000070030076000000")
- (defun sudoku-str->row(str)(DivLst (mapcar 'atoi (mapcar 'chr (vl-string->list str))) 9))
- ;; sudoku-row->col 行表转列表,传入参数 lst
- ;;(setq lst (sudoku-str->row str))
- (defun sudoku-row->col (lst / NL S N)
- (while (car lst)
- (foreach x lst (setq S (cons (car x) S) N (cons (cdr x) N)))
- (setq lst (reverse N) NL (cons (reverse S) NL) S nil N nil)
- )(reverse NL)
- )
- ;; sudoku-row->9gg 行表转宫表,传入参数 lst
- ;;(setq lst (sudoku-str->row str))
- (defun sudoku-row->9gg(lst / SN)
- (foreach x (sudoku-row->col (mapcar '(lambda (x)(DivLst x 3)) lst))
- (setq SN (cons (DivLst (apply 'append x) 9) SN)))
- (apply 'append (reverse SN))
- )
-
- ;;定长分割表函数
- (defun DivLst(lst n / a b)
- (while lst
- (setq b nil i 0)
- (while (< i n) (setq b (cons (car lst) b) lst (cdr lst) i (1+ i)))
- (setq a (cons (reverse b) a))
- )(reverse a)
- )
|