如何用Python按指定行列和规则拼接9个3×3矩阵为9×9矩阵?
解决方案:回溯法+剪枝优化
针对你的问题,暴力随机拼接效率极低,而回溯法结合约束剪枝是更高效的方案——通过提前排除不符合部分约束的排列,避免遍历所有9!种可能。
步骤1:预处理矩阵属性
首先,为每个小矩阵计算关键属性,方便后续快速验证约束:
- 每个小矩阵的3行的和(用于计算大矩阵的行和)
- 每个小矩阵的3列的和(用于计算大矩阵的列和)
- 小矩阵的对角线和(用于大矩阵主对角线总和)
- 小矩阵的反对角线和(用于大矩阵副对角线总和)
步骤2:回溯填充+剪枝
按行优先顺序填充3×3的小矩阵网格,每放置一个矩阵后,立即检查当前已填充部分是否违反约束:
- 若某一行的3个小矩阵已填满,验证对应大矩阵的3行和是否符合目标
- 若某一列的3个小矩阵已填满,验证对应大矩阵的3列和是否符合目标
- 当主对角线的3个小矩阵(M00、M11、M22)都填满时,验证主对角线总和
- 当副对角线的3个小矩阵(M02、M11、M20)都填满时,验证副对角线总和
不符合约束的分支直接回溯,无需继续深入,大幅减少计算量。
完整代码实现
import numpy as np # 定义所有3×3矩阵 matrices = [ np.array([[0, 0, 0], [0, 1, 0], [0, 0, 0]]), # matrix1 np.array([[0, 0, 1], [0, 0, 0], [1, 0, 0]]), # matrix2 np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]]), # matrix3 np.array([[1, 0, 1], [0, 0, 0], [1, 0, 1]]), # matrix4 np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]]), # matrix5 np.array([[1, 1, 1], [0, 0, 0], [1, 1, 1]]), # matrix6 np.array([[1, 1, 1], [1, 0, 0], [1, 1, 1]]), # matrix7 np.array([[1, 1, 1], [1, 0, 1], [1, 1, 1]]), # matrix8 np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]]) # matrix9 ] # 预处理每个矩阵的属性:行和、列和、对角线和、反对角线和 mat_attrs = [] for mat in matrices: row_sums = [sum(row) for row in mat] col_sums = [sum(col) for col in mat.T] diag_sum = sum(mat.diagonal()) anti_diag_sum = sum(mat[:, ::-1].diagonal()) mat_attrs.append((row_sums, col_sums, diag_sum, anti_diag_sum)) # 目标约束 target_row_sums = [9, 4, 9, 5, 2, 5, 4, 3, 4] target_col_sums = [5, 4, 5, 7, 4, 7, 5, 4, 4] target_diag1 = 6 target_diag2 = 6 # 回溯函数 def backtrack(grid, used, pos): # pos是当前要填充的位置索引(0~8,对应3x3网格的行优先顺序) if pos == 9: # 所有矩阵已填充,验证最终约束(其实前面剪枝已经确保符合,这里做最终确认) return verify_full_constraints(grid) row = pos // 3 col = pos % 3 for idx in range(9): if not used[idx]: # 尝试放置当前矩阵到grid[row][col] grid[row][col] = idx used[idx] = True # 检查当前部分约束,剪枝 if check_partial_constraints(grid, used, row, col): # 递归填充下一个位置 result = backtrack(grid, used, pos + 1) if result is not None: return result # 回溯 grid[row][col] = -1 used[idx] = False return None def check_partial_constraints(grid, used, row, col): # 检查当前行的小矩阵是否填满,验证对应大矩阵的3行和 if all(grid[row][c] != -1 for c in range(3)): # 计算大矩阵的row*3, row*3+1, row*3+2行的和 for i in range(3): total = 0 for c in range(3): mat_idx = grid[row][c] total += mat_attrs[mat_idx][0][i] if total != target_row_sums[row*3 + i]: return False # 检查当前列的小矩阵是否填满,验证对应大矩阵的3列和 if all(grid[r][col] != -1 for r in range(3)): # 计算大矩阵的col*3, col*3+1, col*3+2列的和 for i in range(3): total = 0 for r in range(3): mat_idx = grid[r][col] total += mat_attrs[mat_idx][1][i] if total != target_col_sums[col*3 + i]: return False # 检查主对角线(M00, M11, M22)是否填满,验证主对角线总和 if row == col and all(grid[r][r] != -1 for r in range(3)): total = 0 for r in range(3): mat_idx = grid[r][r] total += mat_attrs[mat_idx][2] if total != target_diag1: return False # 检查副对角线(M02, M11, M20)是否填满,验证副对角线总和 if row + col == 2 and all(grid[r][2 - r] != -1 for r in range(3)): total = 0 for r in range(3): mat_idx = grid[r][2 - r] total += mat_attrs[mat_idx][3] if total != target_diag2: return False return True def verify_full_constraints(grid): # 构建最终的9×9矩阵(可选,用于输出结果) big_mat = np.zeros((9,9), dtype=int) for r in range(3): for c in range(3): mat_idx = grid[r][c] big_mat[r*3:(r+1)*3, c*3:(c+1)*3] = matrices[mat_idx] # 验证所有约束(可选,确保结果正确) assert np.array_equal(big_mat.sum(axis=1), target_row_sums) assert np.array_equal(big_mat.sum(axis=0), target_col_sums) assert big_mat.diagonal().sum() == target_diag1 assert big_mat[::-1].diagonal().sum() == target_diag2 return grid, big_mat # 初始化网格(-1表示未填充)和已使用标记 initial_grid = [[-1]*3 for _ in range(3)] initial_used = [False]*9 # 执行回溯 result = backtrack(initial_grid, initial_used, 0) if result: grid, big_mat = result print("找到符合条件的小矩阵排列(3×3网格,数字对应matrix1~matrix9的编号):") for row in grid: print([idx+1 for idx in row]) print("\n拼接后的9×9矩阵:") print(big_mat) else: print("未找到符合条件的排列(若你确认纸上存在,可检查矩阵编号对应是否有误)")
代码说明
- 预处理阶段:提前计算每个小矩阵的行和、列和等属性,避免重复计算,提升验证效率。
- 剪枝逻辑:每放置一个矩阵后,立即检查已填充的行/列/对角线是否符合约束,不符合则直接回溯,跳过无效分支。
- 结果验证:找到候选排列后,构建完整9×9矩阵并验证所有约束,确保结果正确。
运行代码后,会输出小矩阵的排列顺序以及最终拼接的9×9矩阵,完全匹配你给出的约束条件。
内容的提问来源于stack exchange,提问作者user12471498
相关产品推荐
相关产品推荐

