首页 > 技术文章 > 回溯法——数独游戏

sunny0824 2020-08-17 11:04 原文

一、问题描述

数独(Sudoku)是一款大众喜爱的数字逻辑游戏。玩家需要根据9X9盘面上的已知数字,推算出所有剩余空格的数字,并且满足每一行、每一列、每一个粗线宫内的数字均含1-9,并且不重复。
输入:
包含已知数字的9X9盘面数组[空缺位以数字0表示]
输出:
完整的9X9盘面数组

输入示例:

0 9 2 4 8 1 7 6 3
4 1 3 7 6 2 9 8 5
8 6 7 3 5 9 4 1 2
6 2 4 1 9 5 3 7 8
7 5 9 8 4 3 1 2 6
1 3 8 6 2 7 5 9 4
2 7 1 5 3 8 6 4 9
3 8 6 9 1 4 2 5 7
0 4 5 2 7 6 8 3 1

 输出示例:

5 9 2 4 8 1 7 6 3
4 1 3 7 6 2 9 8 5
8 6 7 3 5 9 4 1 2
6 2 4 1 9 5 3 7 8
7 5 9 8 4 3 1 2 6
1 3 8 6 2 7 5 9 4
2 7 1 5 3 8 6 4 9
3 8 6 9 1 4 2 5 7
9 4 5 2 7 6 8 3 1

 二、思路

对于这个题我们的第一思路当然是用深度遍历回溯法来完成。

首先将数字存在9*9的二维数组数据结构内,其次寻找值为0的元素,将其换成1到9任一个数字。

  若能满足称为数独的三个条件,则继续往下搜索值为0的元素。

    同样将其换成0到9之间的任意数字,若发现所有的数字都不满足条件的话,则回溯到上一个点,并把该点的值继续换成其他数字。

  直到所有的81个点都遍历完,若遍历完发现没有满足条件的值可以填满值为0的位子,则返回False。

三、代码实现

首先我们先写一个函数来判断数字num是否可以放到9*9矩阵的(row,col)位置上。

def check(matrix,row,col,value):
    """
    检测在(row,col)放value是否合适
    1.每行含1-9,不含重复值value
    2.每列含1-9,不含重复值value
    3.3*3区块含1-9,不含重复值value
    """
    #检测每行
    for j in range(9):
        if matrix[row][j]==value:
            return False
    #检测每列
    for i in range(9):
        if matrix[i][col]==value:
            return False
    # 检测元素所在3*3区域
    area_row=row//3*3
    area_col=col//3*3
    for i in range(area_row,area_row+3):
        for j in range(area_col,area_col+3):
            if matrix[i][j]==value:
                return False
    return True

然后我们就可以用回溯法来完成数独游戏了:

def solveSudoku(matrix,count=0):
    """
    遍历每一个未填元素,遍历1-9替换为合适的数字
    """
    if count==81:#递归出口
        return True
    row=count//9#行标
    col=count%9#列标
    if matrix[row][col]!=0:#已填充
        return solveSudoku(matrix,count=count+1)
    else:#未填充
        for i in range(1,10):
            if check(matrix,row,col,i):#找到可能的填充数
                matrix[row][col]=i
                if solveSudoku(matrix,count=count+1):#是否可完成
                    return True#可完成
                #不可完成
                matrix[row][col]=0#回溯, i换个数继续走
        return False#不可完成

matrix=[]
for i in range(9):
    matrix.append(list(map(int,input().split())))
# print(matrix)
solveSudoku(matrix,0)
# print(solveSudoku(matrix,0))
# for i in range(9):
#     print (' '.join(map(str,matrix[i])))
# print(matrix)
for li in matrix:
    print(' '.join(list(map(str,li))))

 

这里值得注意的一点是,我们可以用递归函数来判断,若我们将当前点的值设为 i 时,其余点是否可以完成数独游戏,即:

for i in range(1,10):
            if check(matrix,row,col,i):#找到可能的填充数
                matrix[row][col]=i
                if solveSudoku(matrix,count=count+1):#是否可完成
                    return True#可完成

如果不能完成的话,则回溯,我们这里只需要将 matrix[row][col]设为0,然后让他接着遍历0-9中的其余数即可。

 

推荐阅读