摒弃法解决数独问题sudoku,附python实现

定义

数独是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复 。
数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。

算法思想

上一篇文章利用了深度优先搜索,递归实现了解决数独问题。现考虑其他算法思想解决数独问题。
摒弃法:摒弃法也称等位群格位算法,是模拟人求解数独时的思维方法。按照行、列、粗线格唯一值的原则,将现有三个方向已有数据分步排除抛弃的方法,剩下数即为所填数。
缺点:只能解决简单数独,对于复杂数独,即一个位置可能有多个解并且解不是所有可填数中最小的数时才能得到结果。

# -*- coding: utf-8 -*-
# @Time    : 2022/4/30 17:10
# @Author  : kunkun
# @File    : algorithm2.py
# ------------------------------
# 数独算法2,摒弃法,只能求解简单数独
# 算法思想:摒弃法也称等位群格位算法,是模拟人求解数独时的思维方法。
# 照行、列、粗线格唯一值的原则,将现有三个方向已有数据分步排除抛弃的方法,剩下数即为所填数。
import numpy as np

sudoku = np.zeros((9, 9), dtype=np.int32)  # 存储数独矩阵
mark = np.zeros((81, 11), dtype=np.int32)  # 标记数组,mark[i][0]与sudoku元素一一对应,mark[i][i]-mark[i][9]存储1~9,mark[10]标记是否得出解
count = 0  # 记录已填空的数量


def ini():
    global count
    global sudoku
    sudoku = [[0, 0, 0, 0, 0, 0, 0, 0, 4],
              [0, 2, 8, 7, 5, 0, 0, 3, 0],
              [0, 3, 1, 0, 0, 2, 0, 0, 0],
              [6, 5, 0, 2, 3, 7, 0, 0, 0],
              [0, 0, 0, 0, 9, 0, 0, 0, 0],
              [0, 0, 0, 6, 8, 1, 0, 5, 9],
              [0, 0, 0, 9, 0, 0, 8, 6, 0],
              [0, 9, 0, 0, 2, 4, 3, 1, 0],
              [5, 0, 0, 0, 0, 0, 0, 0, 0]]

    for i in range(81):  # 初始化mark数组
        if sudoku[i // 9][i % 9] != 0:
            count += 1  # 记录count
            mark[i][0] = sudoku[i // 9][i % 9]
            mark[i][10] = 1
        for j in range(1, 10):
            mark[i][j] = j
    # print(count)


def bqf():
    global count
    while count < 81:
        count_old = count
        for i in range(81):
            if mark[i][10] == 0:
                # print('i', i)
                # 去除行中出现的数字
                for j in range(9):
                    if 1 <= sudoku[i // 9][j] <= 9:
                        mark[i][sudoku[i // 9][j]] = 0
                # 去除列中重复数字
                for j in range(9):
                    if 1 <= sudoku[j][i % 9] <= 9:
                        mark[i][sudoku[j][i % 9]] = 0
                # 去除九宫格中的重复数字
                start_row = i // 9 // 3
                start_cul = i % 9 // 3
                # print('start', start_row, start_cul)
                for j in range(start_row * 3, start_row * 3 + 3):
                    for k in range(start_cul * 3, start_cul * 3 + 3):
                        if 1 <= sudoku[j][k] <= 9:
                            mark[i][sudoku[j][k]] = 0
                # print(mark[i])
                # 计算剩余可填数字的个数
                tmp = 0
                index = 0
                for j in range(1, 10):
                    if mark[i][j] == 0:
                        tmp += 1
                    else:
                        index = j
                if tmp == 8:
                    mark[i][0] = index
                    sudoku[i // 9][i % 9] = index
                    mark[i][index] = 0
                    mark[i][10] = 1
                    count += 1
                    # print(i // 9, i % 9, index)
                # print('tmp', tmp)
                # print('index', index)
        if count == count_old:
            print("No Simple Solution")
            break


if __name__ == '__main__':
    ini()
    bqf()
    for i in range(9):
        print(sudoku[i])

总结

摒弃法比递归的方法更符合人类的思维模式,但是只能解决简单数独,这是一个问题。接下来,我将从摒弃法中得到灵感,改进摒弃法,实现可以解决非简单数独的版本。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值