游戏:数独

序言:
本文记录了用穷举法解数独。

0. 规则
对下面这个9 × 9的方格盘:在这里插入图片描述

有些格子是已经填上数字的,有些格子是空白的。解题者需要在空白的格子填上数字(1-9之间),使得每一行每一列每一小九宫格内的数字不重复。注意,方格盘内所有数子均在1-9之间。

1. 思路
(1)方格盘边长N = 9,小九宫边长n = 3
(2)对每个格子标号,左上角为 ( 0 , 0 ) \red{(0, 0)} (0,0),往右横坐标递增,往下纵坐标递增,右下角为 ( 8 , 8 ) \red{(8, 8)} (8,8)
(3)按照自左向右,自上而下顺序,对于每个空白的格子,尝试填入1-9。
举例:比如现在要在左上角第一个格子,也就是 ( 0 , 0 ) \red{(0, 0)} (0,0)这个格子填数字,遍历1-9这9个数字,它们填入之前必须满足

  • 在第0行里没出现过;
  • 在第0列里没出现过;
  • 在第0个小九宫格里面没出现过。

如不满足它便不能够被填入。
(4)如果有数字能够满足上述3个要求,比如,我们可以在 ( 0 , 0 ) \red{(0, 0)} (0,0)这个格子填 ‘1’ 或 ‘6’。对于这种多种选择的,这里就可以先可以暂且填 ‘1’,然后继续往下填,直到某个格子没有选择了,也就是说1-9都填不进去的时候,说明刚才填’1’的策略不对,是条死路。这时候就要倒退回去,把’1’拿走,填’6’再往下做尝试。即,回溯法。

2. Python实现
(1)方格盘用二维列表maze存储,空白格子用’0’表示
(2)3个判断。对于某一格子 ( r , c ) \red{(r, c)} (r,c)

  • 所在行:maze[r]
  • 所在列:[i[c] for i in maze]
  • **当前小九宫格: [i[j] for j in range(c_beg, c_beg + n) for i in maze[r_beg: r_beg + n]]
    • c_beg = r // n * n, r_beg = c // n * n 分别是当前小九宫格左上角格子的横、纵坐标
    • n = 3 是小九宫格的边长

取小九宫格这个确实理解起来比较困难,需要画个图多思考一下。
以上三点能表示出来,后面就全部交给回溯法:

python3代码:

n = 3
N = n * n
a = [N * [0] for j in range(N + 1)]


def print_maze():
    print('— ' * N)
    for i in range(0, N):
        for j in range(0, N):
            if a[i][j] == 0:
                print(' ', end='')
            else:
                print(a[i][j], end='')
            if j % n != (n - 1):
                print(' ', end='')
            else:
                print('|', end='')
        print()
        if i % n == n - 1:
            print('— ' * N)
def get_sub(r: int, c: int)->list:
    r_beg = int(r // n) * n
    c_beg = int(c // n) * n

    return [i[j] for j in range(c_beg, c_beg + n) for i in a[r_beg:r_beg + n]]
def check(arr: list, k)-> bool:
    return not k in arr
def dfs(r: int, c: int):
    if r == N:
        print_maze()
        return
    if c == N:
        dfs(r + 1, 0)
        return
    if a[r][c] == 0:
        for k in range(1, N + 1):
            row = a[r] # 当前行
            col = [i[c] for i in a] # 当前列
            '''截取子九宫'''
            sub = get_sub(r, c)
            if check(row, k) and check(col, k) and check(sub, k):
                a[r][c] = k
                dfs(r, c + 1)
                a[r][c] = 0
    else:
        dfs(r, c + 1)


if __name__ == '__main__':
    with open(r'test.txt', 'r') as f:
        lines = f.readlines()
        for i in range(len(lines)):
            a[i] = [int(j) for j in lines[i].split()]

    beg_r = 0
    beg_c = 0
    print('题目: ')
    print_maze()
    print('答案: ')
    dfs(beg_r, beg_r)


3. 解题示例
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值