数独问题就是将9×9的网格填充上1~9的整数值,同时保证每个整数在每一行、每一列和每个3×3方格只出现一次。网格中分布有一些线索,你的任务就是填充剩余的网格数字。对于此问题,可以使用0-1变量优化求解。
标准数独问题只要有解就行,无需设置目标函数,即:可行解就是数独问题的解。
1.对于给定的初始元素,都认为是等式约束:
x i j k = 1 ∀ k = c i j ∈ C {{x}_{ijk}}=1\quad \forall k={{c}_{ij}}\in C xijk=1∀k=cij∈C
2.所有格子只能取一个值:
∑ k = 1 9 x i j k = 1 ∀ i , j = 1 , 2 , … 9 \sum\limits_{k=1}^{9}{{{x}_{ijk}}=1\quad \forall i,j=1,2,\ldots 9} k=1∑9xijk=1∀i,j=1,2,…9
3.每个数字在同一行、同一列、同一个九宫格只能出现一次:
∑ j = 1 9 x i j k = 1 ∀ i , k = 1 , 2 , … 9 \sum\limits_{j=1}^{9}{{{x}_{ijk}}=1\quad \forall i,k=1,2,\ldots 9} j=1∑9xijk=1∀i,k=1,2,…9
∑ i = 1 9 x i j k = 1 ∀ j , k = 1 , 2 , … 9 \sum\limits_{i=1}^{9}{{{x}_{ijk}}=1\quad \forall j,k=1,2,\ldots 9} i=1∑9xijk=1∀j,k=1,2,…9
∑ i = 1 + 3 × I 3 + 3 × I ∑ j = 1 + 3 × J 3 + 3 × J x i j k = 1 ∀ k = 1 , 2 , … 9 ; I , J = 0 , 1 , 2 \sum\limits_{i=1+3\times I}^{3+3\times I}{\sum\limits_{j=1+3\times J}^{3+3\times J}{{{x}_{ijk}}=1\quad \forall k=1,2,\ldots 9;I,J=0,1,2}} i=1+3×I∑3+3×Ij=1+3×J∑3+3×Jxijk=1∀k=1,2,…9;I,J=0,1,2
from gurobipy import *
import pandas as pd
def sudoku(matrix):
# 创建模型
model = Model('solve_sudoku')
# 创建变量
x = model.addVars(9, 9, 9, vtype=GRB.BINARY)
# 更新变量环境
model.update()
# 创建目标函数
model.setObjective(1, GRB.MINIMIZE)
# 创建约束条件
model.addConstrs(x[i, j, k] == 1 for i in range(9) for j in range(9) for k in range(9)
if isinstance(matrix.at[i, j], int) and k == matrix.at[i, j] - 1)
model.addConstrs(sum(x.select(i, j, '*')) == 1 for i in range(9) for j in range(9))
model.addConstrs(sum(x.select(i, '*', j)) == 1 for i in range(9) for j in range(9))
model.addConstrs(sum(x.select('*', i, j)) == 1 for i in range(9) for j in range(9))
model.addConstrs(sum(x[i + 3 * I, j + 3 * J, k] for i in range(3) for j in range(3)) == 1
for k in range(9) for I in range(3) for J in range(3))
# 执行线性规划模型
model.optimize()
# 输出结果
result = pd.DataFrame()
for k, v in model.getAttr('x', x).items():
if v == 1:
result.at[k[0], k[1]] = k[2] + 1
return result.astype(int)
if __name__=='__main__':
matrix = pd.read_excel('F:\python\Gurobi_test\sudoku_test.xlsx', index_col=False, header=None, na_filter=False)
print(sudoku(matrix))
九宫格中的数字可以进行自定义,替换成你想要的数字。只要是标准数独问题,此程序均可以处理,而且使用Gurobi处理优化问题性能很高。
如何安装和快速入门Gurobi?请参考gurobi 高效数学规划引擎