递归 | HJ44 Sudoku

# 最优解
class Solution:
 
    def isValue(self, board, x, y):
        # 检查已经填入的坐标是否和列中有的元素相等
        for i in range(9):
            if i != x and board[i][y] == board[x][y]:
                return False
        # 检查已经填入的坐标是否和行中有的元素相等
        for j in range(9):
            if j != y and board[x][j] == board[x][y]:
                return False
 
        # 检查每个正方形是否符合(粗线框内只有1~9)
        m, n = 3*(x // 3), 3*(y // 3)  # 这里求出的是3x3网格的左上角的坐标
        for i in range(3):
            for j in range(3):
                if(i+m != x or j+n != y) and board[i+m][j+n] == board[x][y]:
                    return False 
 
        return True
 
    def dfs(self, board):
 
        for i in range(9):
            for j in range(9):
                if board[i][j] == 0:
                    for k in '123456789':  # 从里面选择一个
                        board[i][j] = int(k)
                        if self.isValue(board, i, j) and self.dfs(board):
                            return True
                        # 回溯
                        board[i][j] = 0
                    # 都不行,说明上次的数字不合理
                    return False
        # 全部便利完,返回True
        return True
 
while True:
    try:
        board = []
        for i in range(9):
            row = list(map(int, input().split()))
            board.append(row)
 
        s = Solution()
        s.dfs(board)
 
        for i in range(9):
            board[i] = list(map(str, board[i]))
            print(' '.join(board[i]))
    except:
        break

# 我的代码(原本不通过,5/6,加入最优解的递归后通过)
import copy
def set_value(board, blanks, d, left):
    N = {"1", "2", "3", "4", "5", "6", "7", "8", "9"}
    for x, y in blanks:
        if d[x, y] == set():
            continue
        # 3*3方块内
        cube = []
        for i in range(x // 3 * 3, x // 3 * 3 + 3):
            for j in range(y // 3 * 3, y // 3 * 3 + 3):
                cube.append(board[i][j])
        d[x, y] = d[x, y] & (N - set(cube)) if d[x, y] else N - set(cube)
        # 交叉行列内
        row, col = board[x], [row[y] for row in board]
        d[x, y] &= (N - set(row)) & (N - set(col))
        # 3*3方块内另两行两列
        pal_r1, pal_r2 = [num for num in range(3) if num != x % 3]
        pal_c1, pal_c2 = [num for num in range(3) if num != y % 3]
        pal_r1, pal_r2 = board[x // 3 * 3 + pal_r1], board[x // 3 * 3 + pal_r2]
        pal_c1, pal_c2 = [row[y // 3 * 3 + pal_c1] for row in board], [
            row[y // 3 * 3 + pal_c2] for row in board
        ]
        for choice in d[x, y]:
            if choice in pal_r1 and choice in pal_r2:
                cube_blank = [
                    j
                    for j in range(y // 3 * 3, y // 3 * 3 + 3)
                    if board[x][j] == "0" and j != y
                ]
                if len(cube_blank) == 0:
                    d[x, y] = {choice}
                    break
                elif len(cube_blank) == 1:
                    another_col = [row[cube_blank[0]] for row in board]
                    if choice in another_col:
                        d[x, y] = {choice}
                        break
                elif len(cube_blank) == 2 and choice in pal_c1 and choice in pal_c2:
                    d[x, y] = {choice}
                    break
            elif choice in pal_c1 and choice in pal_c2:
                cube_blank = [
                    i
                    for i in range(x // 3 * 3, x // 3 * 3 + 3)
                    if board[i][y] == "0" and i != x
                ]
                if len(cube_blank) == 0:
                    d[x, y] = {choice}
                    break
                elif len(cube_blank) == 1:
                    another_row = board[cube_blank[0]]
                    if choice in another_row:
                        d[x, y] = {choice}
                        break
                elif len(cube_blank) == 2 and choice in pal_r1 and choice in pal_r2:
                    d[x, y] = {choice}
                    break

        if len(d[x, y]) == 1:
            board[x][y] = d[x, y].pop()
            left -= 1
    return left


def is_valid(board, x, y):
    for i in range(9):  # 检查列
        if i != x and board[i][y] == board[x][y]:
            return False
    for j in range(9):
        if j != y and board[x][j] == board[x][y]:
            return False
    for i in range(x // 3 * 3, x // 3 * 3 + 3):
        for j in range(y // 3 * 3, y // 3 * 3 + 3):
            if (i != x and j != y) and board[x][y] == board[i][j]:
                return False
    return True


def dfs(board, blanks, d):
    for x, y in blanks:
        if board[x][y] != "0":
            continue
        for v in d[x, y]:
            board[x][y] = v
            if is_valid(board, x, y) and dfs(board, blanks, d):
                return True
            board[x][y] = "0"
        return False
    # 全部遍历完返回true
    return True


while True:
    try:
        board = []
        blanks = []
        for i in range(9):
            row = input().split(" ")
            board.append(row)
            for j, num in enumerate(row):
                if num == "0":
                    blanks.append((i, j))
        d = dict.fromkeys(blanks)
        left = len(blanks)
        while left:
            left_tmp = set_value(board, blanks, d, left)
            if left == left_tmp:  # 陷入死局,一个没填
                board_copy, blanks_copy, d_copy = (
                    copy.deepcopy(board),
                    copy.deepcopy(blanks),
                    copy.deepcopy(d),
                )
                dfs(board_copy, blanks_copy, d_copy)
                board = board_copy
                break
            else:
                left = left_tmp
        for row in board:
            print(" ".join(map(str, row)))

    except:
        break


用时:4h

华为笔试刷题 文章被收录于专栏

高质量题: 1~40:HJ16,HJ22,HJ24,HJ26,HJ27,HJ28,HJ35,HJ37,HJ39; 40~80:HJ41,HJ42,HJ43,HJ44,HJ48,HJ50,HJ52,HJ53,HJ57,HJ61,HJ63,HJ64,HJ70,HJ71,HJ74,HJ77; 80~108:HJ82,HJ85,HJ88,HJ89,HJ93,HJ95,HJ98,HJ103,HJ107

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务