组内题:数独问题python(深度优化搜索算法)

组内出题:

判定一个数独是否有效,正确。
该数独只填充了部分数字,其中缺少的数字用 .表示。

一个合法的数独是否有效(部分填充)并不一定是可解的.仅需要使填充的空格有效即可.

 

备注:

数独是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复。

数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。

仅限python.

 

我的代码:

import time

def make_dic_key(A, B):  #生成['A1', 'A2', 'A3',... 'I1', 'I2', 'I3',]字典key列表
    return [a+b for a in A for b in B]

def nine_list(cols, rows):
    list_cols = [make_dic_key(rows, c) for c in cols]   # 生成列字典key
    list_rows = [make_dic_key(r, cols) for r in rows]   # 生成行字典key
    list_nine_squares = [make_dic_key(r, c) for r in ('ABC', 'DEF', 'GHI') for c in('123', '456', '789')] #生成九宫格字典key
    return list_cols + list_rows + list_nine_squares

cols = '123456789'
rows = 'ABCDEFGHI'
squares_no = make_dic_key(rows, cols)     # 编号:['A1', 'A2',... 'A9', ... , 'I8', 'I9']
nine_units = nine_list(cols,rows)   # 所有单元列表(9行,9列,9宫格)
cor_unit = dict((s, [u for u in nine_units if s in u]) for s in squares_no) # cor_unit表示 某个元素编号相关的3个单元列表
# 表示某个元素编号:与之相关的20个元素编号
cor_no = dict((s, set(sum(cor_unit[s], []))-set([s])) for s in squares_no)

def dowork_data(data):     # 处理数据
    values = dict((s, cols) for s in squares_no)    #{'A1': '123456789', 'A2': '123456789',....}
    dict_data = dict(zip(squares_no, data))     # {'A1': '4', 'A2': '.', ... , 'I8': '.', 'I9': '.'}
    for key, value in dict_data.items():
        #print(key, value)
        #print('aaaaaaaaaa')
        if value in cols and not replace_ele(values, key, value):
            return False
    return values


def replace_ele(values, key, value):  # values[key]删除除了value以外的值
    other_values = values[key].replace(value, '')   #把values中value删除
    #print('&&&')
    #print(other_values)
    #print('&&&')
    if all(delete_num(values, key, num) for num in other_values):
        return values
    else:
        return False

def delete_num(values, key, num):        # values[key]中删除值num
    if num not in values[key]:
        return values
    values[key] = values[key].replace(num, '')
    # 如果一个位置只有一个可能值,这个值从对应的相关位置的可能值中去除
    if len(values[key]) == 0:
        return False
    elif len(values[key]) == 1:
        only_value = values[key]
        # 相关的20个元素中删除only_value
        if not all(delete_num(values, s, only_value) for s in cor_no[key]):
            return False
    # 如果一个unit只有一个可能位置来放某个值,把值放那
    for ele_list in cor_unit[key]:
        dplaces = [s for s in ele_list if num in values[s]]  # 找到可能存放的位置
        if len(dplaces) == 0:
            return False
        elif len(dplaces) == 1:
            only_key = dplaces[0]
            if not replace_ele(values, only_key, num):
                return False
    return values


def search_data(values):    #递归循环
    if values is False:
        return False
    if all(len(values[s]) == 1 for s in squares_no):
        return values
    n, key = min((len(values[key]), key) for key in squares_no if len(values[key]) > 1)
    resultlist=[]
    for num in values[key]: # 用可能取值最小的优先遍历
        resultlist.append(search_data(replace_ele(values.copy(), key, num)))
    return find_result(resultlist)

def find_result(values):
    for result in values:
        if result:
            return result
    return False


def show_data(data):
    if not data:
        print('此数独无解')
        return
    temp = []
    for key, value in data.items():
        temp.append(value)
    j = 0
    for i in range(0,9):
        print(temp[j:j+9])
        j = j+9
    return


if __name__ == '__main__':
    data1 = [5, 3, 0, 0, 7, 0, 0, 0, 0,
          6, 0, 0, 1, 9, 5, 0, 0, 0,
          0, 9, 8, 0, 0, 0, 0, 6, 0,
          8, 0, 0, 0, 6, 0, 0, 0, 3,
          4, 0, 0, 8, 0, 3, 0, 0, 1,
          7, 0, 0, 0, 2, 0, 0, 0, 6,
          0, 6, 0, 0, 0, 0, 2, 8, 0,
          0, 0, 0, 4, 1, 9, 0, 0, 5,
          0, 0, 0, 0, 8, 0, 0, 7, 9]
    data2 = (str(s) for s in data1)
    start = time.clock()
    values = dict((s, cols) for s in squares_no)
    result = search_data(dowork_data(data2))
    end = time.clock()
    show_data(result)
    print("时间: %f" % (end - start))

 

运行结果:

['5', '3', '4', '6', '7', '8', '9', '1', '2']
['6', '7', '2', '1', '9', '5', '3', '4', '8']
['1', '9', '8', '3', '4', '2', '5', '6', '7']
['8', '5', '9', '7', '6', '1', '4', '2', '3']
['4', '2', '6', '8', '5', '3', '7', '9', '1']
['7', '1', '3', '9', '2', '4', '8', '5', '6']
['9', '6', '1', '5', '3', '7', '2', '8', '4']
['2', '8', '7', '4', '1', '9', '6', '3', '5']
['3', '4', '5', '2', '8', '6', '1', '7', '9']
时间: 0.003033

 

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值