python 实现 数独 解法 (穷举法)

  • 2012-10-07

长假无聊,玩数独,写了个解的程序,还有改进的余地,请大家拍砖... 第二个脚本优化了数独解法的算法 第三个脚本再一次优化了数独解法的算法并修复某行没有提示时导致的一个bug [2012-12-15 16:45] 后续会陆续给出如何制作一个数独,并配合解法一起,有设有解。

  • 2016-10-06

无意中看到4年前的这段代码,使用起来不怎么方便。增加了命令行输入残缺数独的功能。

# -*- coding: utf-8 -*-
'''
Created on 2012-10-5
[@author](https://my.oschina.net/arthor): Administrator
'''
from collections import defaultdict
import itertools
import time
import gc
import operator
import profile
 
gc.disable()

a = [
[ 0, 3, 9, 0, 0, 0, 6, 1, 0 ], 
[ 7, 0, 0, 3, 0, 8, 0, 0, 4 ], 
[ 1, 0, 0, 0, 9, 0, 0, 0, 8 ], 
[ 0, 1, 0, 9, 0, 7, 0, 4, 0 ], 
[ 0, 0, 3, 0, 2, 0, 9, 0, 0 ], 
[ 0, 4, 0, 8, 0, 5, 0, 2, 0 ], 
[ 6, 0, 0, 0, 4, 0, 0, 0, 2 ],  
[ 3, 0, 0, 6, 0, 1, 0, 0, 9 ], 
[ 0, 9, 7, 0, 0, 0, 8, 6, 0 ]  
# 0, 1, 2, 3,|4, 5, 6,|7, 8
     ]

h_d = {}
 
def filter_by_column(y, resource_dict):
    '''[@summary](https://my.oschina.net/u/203623): 纵向过滤重复的值
    [@param](https://my.oschina.net/u/2303379) y: 待检测的一行排列
    [@param](https://my.oschina.net/u/2303379) resource_dict: 列序号及组合在对应列号的值列表
    '''
    if not resource_dict:
        return 1
    return all((y[k] not in  v for k, v in resource_dict.iteritems()))
 
sudokus = []
 
def check_3_lines(f, s, t):
    '''[@summary](https://my.oschina.net/u/203623): 检测3行的每三列是不是符合条件
    @param f: first line
    '''
    if len(set((f[0], f[1], f[2], s[0], s[1], s[2], t[0], t[1], t[2]))) != 9:
        return 1
    if len(set((f[3], f[4], f[5], s[3], s[4], s[5], t[3], t[4], t[5]))) != 9:
        return 1
    if len(set((f[6], f[7], f[8], s[6], s[7], s[8], t[6], t[7], t[8]))) != 9:
        return 1
    return 0
 
def check_2_lines(f, s):
    '''@summary: 检测两行数据的每三列是不是有重复值,提前淘汰有重复值的组合
    @param f: first line
    '''
    if len(set((f[0], f[1], f[2], s[0], s[1], s[2]))) != 6:
        return 1
    if len(set((f[3], f[4], f[5], s[3], s[4], s[5]))) != 6:
        return 1
    if len(set((f[6], f[7], f[8], s[6], s[7], s[8]))) != 6:
        return 1
    return 0
 
def solve_sudoku(h_d, h_idx=None, reserves=None
                 , solves=None, resource_dict=None):
    '''
    @param reserves: 已经验证过符合条件的排列
    @param solves: 最终的解决方案集合
    @param resource_dict: dict key in range(1,10),values 是每行同一列的数字的列表
    '''
    if solves is None:
        solves = []
     
    if h_idx is None :
        h_idx = 0
    for l0 in h_d[h_idx]:
        if reserves == None:
            _reserves = [l0, ]
            solve_sudoku(h_d, h_idx + 1, _reserves, solves)
        else:
            if not filter_by_column(l0, resource_dict):
                continue
            if h_idx in (1 , 4, 7):
                if check_2_lines(reserves[h_idx - 1], l0):
                    continue
            elif h_idx in (2, 5, 8) :
                if check_3_lines(reserves[h_idx - 2], reserves[h_idx - 1], l0):
                    continue
                     
            _reserves = list(reserves)
            _reserves.append(l0)
            if h_idx < 8:
                solve_sudoku(h_d, h_idx + 1, _reserves, solves
                             , dict((idx, set([i[idx] for i in _reserves])) 
                                    for idx in range(0, 9)))
            if h_idx == 8:
                solves.append(_reserves)
                print u"calc No. {num} result".format(num=len(solves))
                print u"*" * 50
                for i in solves[-1]:
                    print i
                 
    else:
        if h_idx == 0:
            return solves
                 
if __name__ == '__main__':

    print "input incomplete sudoku matrix, blank is 0,split row spearated by comma "
    s = raw_input(">")
    print s
    input_rows = s.split(",")


    a = map(lambda x:list(map(lambda y:int(y),x)),input_rows)
    

    #===============================================================================
    # 得到坐标点和值,相当于稀疏矩阵:(X,Y):value
    #===============================================================================
    exists_d = dict(((h_idx, y_idx), v) 
                    for h_idx, y in enumerate(a) 
                    for y_idx , v in enumerate(y)  if v)
     
     
    h_exist = defaultdict(dict)
    v_exist = defaultdict(dict)
     
    #===============================================================================
    # 二维数组
    #===============================================================================
    for k, v in exists_d.iteritems():
        h_exist[k[0]][k[1]] = v
        v_exist[k[1]][k[0]] = v
     
    #===============================================================================
    # 生成所有的组合
    #===============================================================================
    permutations = tuple(itertools.permutations(range(1, 10), 9))
          
    #===============================================================================
    # 取得行号与该行符合条件的组合
    #===============================================================================
    for hk, hv in h_exist.iteritems():
         
        #===========================================================================
        # 过滤横向,x轴与同行已知的点的值重复的组合
        #===========================================================================
        q = filter(lambda x:all((x[k] == v 
                                 for k, v in hv.iteritems())), permutations)
         
        #===========================================================================
        # 过滤纵向,Y轴与同列已知的点的值重复的组合
        #===========================================================================
        q = filter(lambda x:all((x[vk] != v 
                                 for vk , vv in v_exist.iteritems() 
                                 for k, v in vv.iteritems() 
                                 if k != hk)), q)
         
        h_d[hk] = q
     
    #===============================================================================
    # 不全某行没有任何提示
    #===============================================================================
    for line_idx in range(0, 9):
        if line_idx not in h_d:
            h_d[line_idx] = permutations

    now = time.time()
    print time.time() - now 
    now = time.time()
    x = solve_sudoku(h_d)
    print time.time() - now
    print x
 

增加了手动录入缺失矩阵的功能。原先分享的代码见

转载于:https://my.oschina.net/corleone/blog/754775

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值