From bd3ddf873d64cd522e0198895b88616eb5b4caf5 Mon Sep 17 00:00:00 2001 From: 2400010791-L <3555712249@qq.com> Date: Tue, 3 Jun 2025 17:58:18 +0800 Subject: [PATCH] Add files via upload --- openjudge/1983/1983/2400010791.md | 18 ++++ openjudge/1983/1983/2400010791.py | 163 ++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 openjudge/1983/1983/2400010791.md create mode 100644 openjudge/1983/1983/2400010791.py diff --git a/openjudge/1983/1983/2400010791.md b/openjudge/1983/1983/2400010791.md new file mode 100644 index 00000000..b7174501 --- /dev/null +++ b/openjudge/1983/1983/2400010791.md @@ -0,0 +1,18 @@ +# 状态: [Accepted](http://dsbpython.openjudge.cn/dspythonbook/solution/49269644/) + +``` +基本信息 +#:49269644 +题目:P1150 +提交人:2400010791 吏语涵 +内存:6756kB +时间:82ms +语言:Python3 +提交时间:2025-05-26 00:14:33 +``` + +### 这段DLX版本的代码相比同学的回溯代码,在本质上的关键优势和改进点: +#### 算法复杂度与效率 +DLX(Dancing Links)是Donald Knuth提出的精确覆盖问题的高效解法,它通过巧妙的链表结构实现快速的回溯和剪枝,特别适合数独这类精确覆盖约束的问题。 +之前的回溯代码在最坏情况下搜索空间大,尤其数独较难时回溯深度大,速度较慢。 +DLX通过「列覆盖」操作迅速删除不可能选项,且恢复操作非常高效(通过链表操作的解链与重链),避免重复计算。 diff --git a/openjudge/1983/1983/2400010791.py b/openjudge/1983/1983/2400010791.py new file mode 100644 index 00000000..30319621 --- /dev/null +++ b/openjudge/1983/1983/2400010791.py @@ -0,0 +1,163 @@ +class DLXNode: + def __init__(self): + self.L = self.R = self.U = self.D = self.C = None + self.rowID = -1 + self.colID = -1 + self.size = 0 + +class DLX: + def __init__(self, m): + self.header = DLXNode() + self.m = m # 列数 + self.columns = [DLXNode() for _ in range(m)] + # 初始化列头节点环形链表 + last = self.header + for i, col in enumerate(self.columns): + col.C = col + col.colID = i + col.U = col.D = col + col.size = 0 + last.R = col + col.L = last + last = col + last.R = self.header + self.header.L = last + self.nodes = [] + self.ans = [] + self.row_nodes = [] + + def add_row(self, row_id, cols): + first = None + last = None + for c in cols: + node = DLXNode() + node.rowID = row_id + node.colID = c + col = self.columns[c] + + # 垂直插入节点 + node.U = col.U + node.D = col + col.U.D = node + col.U = node + node.C = col + col.size += 1 + + # 水平连接 + if first is None: + first = node + else: + last.R = node + node.L = last + last = node + + # 形成环形水平链 + if first and last: + first.L = last + last.R = first + self.nodes.append(first) + self.row_nodes.append(first) + + def cover(self, col): + col.R.L = col.L + col.L.R = col.R + i = col.D + while i != col: + j = i.R + while j != i: + j.D.U = j.U + j.U.D = j.D + j.C.size -= 1 + j = j.R + i = i.D + + def uncover(self, col): + i = col.U + while i != col: + j = i.L + while j != i: + j.C.size += 1 + j.D.U = j + j.U.D = j + j = j.L + i = i.U + col.R.L = col + col.L.R = col + + def search(self, k=0): + if self.header.R == self.header: + return True + c = self.header.R + min_size = c.size + col = c + while c != self.header: + if c.size < min_size: + min_size = c.size + col = c + c = c.R + if col.size == 0: + return False + + self.cover(col) + r = col.D + while r != col: + self.ans.append(r) + j = r.R + while j != r: + self.cover(j.C) + j = j.R + if self.search(k+1): + return True + j = r.L + while j != r: + self.uncover(j.C) + j = j.L + self.ans.pop() + r = r.D + self.uncover(col) + return False + +def sudoku_exact_cover(board): + def get_box_num(r, c): + return (r // 3) * 3 + (c // 3) + dlx = DLX(324) + row_mapping = [] + + for r in range(9): + for c in range(9): + for num in range(1, 10): + if board[r][c] != 0 and board[r][c] != num: + continue + row_id = len(row_mapping) + row_mapping.append((r, c, num)) + cols = [ + r * 9 + c, + 81 + r * 9 + (num - 1), + 162 + c * 9 + (num - 1), + 243 + get_box_num(r, c) * 9 + (num - 1) + ] + dlx.add_row(row_id, cols) + + dlx.search() + + result = [[0]*9 for _ in range(9)] + for node in dlx.ans: + r, c, num = row_mapping[node.rowID] + result[r][c] = num + return result + +def main(): + import sys + input = sys.stdin.read + data = input().strip().split() + t = int(data[0]) + idx = 1 + for _ in range(t): + board = [list(map(int, list(data[idx + i]))) for i in range(9)] + idx += 9 + ans = sudoku_exact_cover(board) + for row in ans: + print(''.join(map(str, row))) + +if __name__ == "__main__": + main() \ No newline at end of file