【算法题目】使用Python生成一个数独游戏的棋盘

2023-05-16

难度可以控制,且解法唯一,时间复杂度看运气。

首先,我们定义了一个 SudokuGenerator 类。然后,我们定义了 generate 方法来生成数独游戏。该方法生成了一个 9 × 9 的矩阵,初始值为 ‘.’。接着,使用 solveSudoku 方法来解决数独游戏,并将解决后的结果存放在生成的矩阵中。

在求解数独游戏时,我们使用深度优先搜索算法来实现。对于每个单元格,首先检查它是否有预设值(即是否为 ‘.’),如果有,直接跳过。如果没有,我们随机生成1~9的数字,并检查该数字是否符合数独规则,如果不符合规则,就换一个数字再次尝试,直到找到符合规则的数字。将符合规则的数字填入该单元格,并继续向后搜索,直到搜索完成整个数独游戏。

然后,我们定义了 removeNumbers 方法来删除数独游戏,使难度符合所选根据。在此方法中,我们使用深度优先搜索算法来逐步删除数独游戏中的数字。我们找到所有预设数字的单元格,并随机打乱它们的顺序。然后尝试删除单元格中的数字,并确保解法唯一,如果解法唯一,继续删除数字,否则回退上一个状态。

最后,我们定义了 isUnique 和 solve 方法来解决数独游戏。isUnique 方法用于确定给定的游戏是否具有唯一解。该方法使用深度优先搜索算法,在填写数字的过程中判断是否出现多个解决方案。 solve 方法解决数独游戏,将字符串表示为数独板,并返回解决结果的一个布尔值。

import random


class SudokuGenerator:
    def __init__(self, difficulty):
        # 限制在30和60之间
        if difficulty < 30:
            self.difficulty = 30
        elif difficulty > 60:
            self.difficulty = 60
        else:
            self.difficulty = difficulty

    def generate(self):
        board = [['.' for _ in range(9)] for _ in range(9)]
        self.solveSudoku(board)
        self.removeNumbers(board, self.difficulty)
        return board

    def solveSudoku(self, board):
        def dfs(board, row, col):
            if col == 9:
                return dfs(board, row + 1, 0)
            if row == 9:
                return True
            if board[row][col] != '.':
                return dfs(board, row, col + 1)
            nums = list(range(1, 10))
            random.shuffle(nums)
            for i in nums:
                if not isValid(board, row, col, str(i)):
                    continue
                board[row][col] = str(i)
                if dfs(board, row, col + 1):
                    return True
                board[row][col] = '.'
            return False

        def isValid(board, row, col, c):
            for i in range(9):
                if board[i][col] == c:
                    return False
                if board[row][i] == c:
                    return False
                if board[(row // 3) * 3 + i // 3][(col // 3) * 3 + i % 3] == c:
                    return False
            return True

        dfs(board, 0, 0)

    def removeNumbers(self, board, difficulty):
        def dfs(board, num):
            if num == 0:
                return True
            lst = [(i, j) for i in range(9) for j in range(9) if board[i][j] != '.']
            lst = sorted(lst, key=lambda x: random.random())
            for i, j in lst:
                c = board[i][j]
                board[i][j] = '.'
                if not self.isUnique(board):
                    board[i][j] = c
                elif dfs(board, num - 1):
                    return True
                else:
                    board[i][j] = c
            return False

        dfs(board, difficulty)

    def isUnique(self, board):
        s = ''.join([''.join(row) for row in board])
        solver = SudokuSolver()
        return solver.solve(s)


class SudokuSolver:
    def solve(self, s):
        board = [[s[i * 9 + j] for j in range(9)] for i in range(9)]
        return self.solveSudoku(board)

    def solveSudoku(self, board):
        def dfs(board, row, col):
            if col == 9:
                return dfs(board, row + 1, 0)
            if row == 9:
                return True
            if board[row][col] != '.':
                return dfs(board, row, col + 1)
            for i in range(1, 10):
                if not isValid(board, row, col, str(i)):
                    continue
                board[row][col] = str(i)
                if dfs(board, row, col + 1):
                    return True
                board[row][col] = '.'
            return False

        def isValid(board, row, col, c):
            for i in range(9):
                if board[i][col] == c:
                    return False
                if board[row][i] == c:
                    return False
                if board[(row // 3) * 3 + i // 3][(col // 3) * 3 + i % 3] == c:
                    return False
            return True

        return dfs(board, 0, 0)


generator = SudokuGenerator(50)  # 挖空多少个格子
board = generator.generate()
for row in board:
    print(row)
print(str(board).count("."))

检查时间复杂度:

import time
ties = []
for _ in range(100):
    t0 = time.time()
    generator = SudokuGenerator(60)  # 挖空多少个格子
    board = generator.generate()
    # for row in board:
    #     print(row)
    ties.append(time.time() - t0)

print(max(ties))
print(min(ties))
print(sum(ties) / len(ties))

得到的生成游戏所消耗的时间是:

254.41049194335938
0.02700185775756836
7.814508402347565

最大时间居然需要254秒,需要改进。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【算法题目】使用Python生成一个数独游戏的棋盘 的相关文章

随机推荐