题解 | #Sudoku# 标准回溯 Python3



逐个检查所有的零位置,当发现不满足时,尽早丢弃当前的部分解(分支)即可。所有的待验证部分解由深度优先的序列Q来管理遍历。
import enum
import sys
from collections import deque

# 处理输入
board = list(map(lambda line: list(map(int, line.split(" "))), sys.stdin.readlines()))

# 统计哪些位置需要求解
blank_pos = []
blank_pos2l = {}
L = 0
for irow, row in enumerate(board):
    for icol, char in enumerate(row):
        if char == 0:
            blank_pos.append((irow, icol))
            blank_pos2l[(irow, icol)] = L
            L += 1

# 根据当前解和题面查询某位置的当前值
def lookupB(sln, pos):
    m, n = pos
    return board[m][n] or (sln[blank_pos2l[(m, n)]] if blank_pos2l[(m, n)] < len(sln) else 0)
    
# 3x3 格内坐标转换
def i2mn(m, n, i):
    return (m // 3 * 3+ i // 3, n // 3 * 3 + i % 3)

# 根据当前部分解sln, 检查数字num是否适合填入位置pos
def check(num, pos, sln):
    m, n = pos
    count_row = sum(1 for i in range(9) if lookupB(sln, (m, i)) == num)
    if count_row > 1: return False
    count_col = sum(1 for i in range(9) if lookupB(sln, (i, n)) == num)
    if count_col > 1: return False
    count_blk = sum(1 for i in range(9) if lookupB(sln, i2mn(m, n, i)) == num)
    if count_blk > 1: return False
    return True

# 回溯 / DFS (等价)
Q = deque()
Q.append([])

sln = []
while Q:
    sln = Q.pop()
    l = len(sln)
    if l == L:
        break
    for nxt in range(1, 10):
        nxt_sln = sln + [nxt]
        if check(nxt, blank_pos[l], nxt_sln):
            Q.append(nxt_sln)

# 输出结果
for irow, row in enumerate(board):
    for icol, char in enumerate(row):
        print(
            lookupB(sln, (irow, icol)),
            end=" " if icol < 8 else ("\n" if irow < 8 else ""),
        )


全部评论

相关推荐

湫湫湫不会java:1.在校经历全删了2.。这些荣誉其实也没啥用只能说,要的是好的开发者不是好好学生3.项目五六点就行了,一个亮点一俩行,xxx技术解决,xxx问题带来xxx提升。第一页学历不行,然后啥有价值的信息也没有,到第二页看到项目了,第一个项目九点,第二个项目像凑数的俩点。总体给人又臭又长,一起加油吧兄弟
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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