主要内容

通过整数编程解决Sudoku难题:基于问题

此示例显示如何使用二进制整数程序来解决数独拼图。对于基于求解器的方法,请参阅通过整数编程解决Sudoku难题:基于求解器

你可能已经看到了数独谜题。拼图是填充一个9×9网格,其中整数从1到9填充,以便每个整数只出现一次,每个行,列和主要的3×3平方。网格部分地填充了线索,您的任务是填写其余的网格。

初始拼图

这是一个数据矩阵B.线索。第一行,B(1,2,2),表示第1行,第2列具有线索2.第二行,B(1,5,3),表示第1行,第5列具有线索3.这是整个矩阵B.

B = [1,2,2;1,5,3;1,8,4;2,1,6;2,9,3;3,3,4;3,7,5;4,4,8;4,6,6;5,1,8; 5,5,1; 5,9,6; 6,4,7; 6,6,5; 7,3,7; 7,7,6; 8,1,4; 8,9,8; 9,2,3; 9,5,4; 9,8,2]; drawSudoku(B)此程序列表的%,请参阅此示例的结尾。

此拼图和另一种Matlab®解决方案技术在内克利夫的角落在2009年。

有许多方法可以手动解决数独谜题,以及许多程序化方法。此示例显示了使用二进制整数编程的直接方法。

这种方法特别简单,因为您没有提供解决方案算法。只需表达Sudoku规则,将线索表达为解决方案的约束,然后Matlab产生解决方案。

二进制整数编程方法

关键的想法是将拼图从正方形的9×9网格转换为立方9-×9乘法的二进制值(0或1)。将立方体阵列识别为9个平方网格彼此堆叠,其中每层对应于1到9的整数。顶部网格,阵列的方形层,无论何处都有一个在溶液或线索具有12的情况下,第二层具有1。在溶液或线索具有9的情况下,第九层具有1。

该配方恰恰适用于二进制整数编程。

这里不需要目标函数,也可能是恒定的术语0.问题实际上只是为了找到一个可行的解决方案,这意味着满足所有约束的解决方案。然而,对于在整数编程求解器的内部构建中断,引起溶液速度增加,使用不限于的目标函数。

向Sudoku的规则表达为约束

假设一个解决方案 X 以9×9×9二进制阵列表示。什么属性有什么关系 X 有?首先,2-D网格(I,j)中的每个方块都有一个值,因此三维数组条目中的一个非零元素恰好 X 一世 j 1 X 一世 j 9. 。换句话说,为每一个 一世 j

σ. K. = 1 9. X 一世 j K. = 1

同样,在每一行中 一世 在2-D网格中,从1到9的每个数字中的每个值恰好换句话说,每个数字 一世 K.

σ. j = 1 9. X 一世 j K. = 1

和每个列 j 在2-D网格中具有相同的财产:每个 j K.

σ. 一世 = 1 9. X 一世 j K. = 1

主要的3×3电网具有类似的约束。对于网格元素 1 ≤. 一世 ≤. 3. 1 ≤. j ≤. 3. ,以及每个人 1 ≤. K. ≤. 9.

σ. 一世 = 1 3. σ. j = 1 3. X 一世 j K. = 1

代表所有九个主要网格,只需向每个九个主要网格添加3或6 一世 j 指数:

σ. 一世 = 1 3. σ. j = 1 3. X 一世 + j + V. K. = 1 在哪里 V. ε. { 0. 3. 6. }

表达线索

每个初始值(线索)可以表示为约束。假设这一点 一世 j 线索是 m 对于一些 1 ≤. m ≤. 9. 。然后 X 一世 j m = 1 。约束 σ. K. = 1 9. X 一世 j K. = 1 确保所有其他人 X 一世 j K. = 0. 为了 K. m

Sudoku在优化问题形式

创建优化变量X这是二进制的,大小为9-×9-in-9。

x = Optimvar('X',9,9,9,'类型''整数''indowbound',0,'上行',1);

使用相当任意的目标函数创建优化问题。目标函数可以通过销毁问题的固有对称来帮助解决方案。

sudpuzzle = OptimProblem;mul = sones(1,1,9);mul = cumsum(mul,3);sudpulze.objective = sum(sum(sum(x,1),2)。* mul);

代表总和的约束X在每个坐标方向上是一个。

sudpulzle.constraints.consx = sum(x,1)== 1;sudpulzle.constraints.consy = sum(x,2)== 1;sudpuzzle.constraints.consz = sum(x,3)== 1;

创建大网格和一个概率的约束。

majorg = OptimConstr(3,3,9);为了U = 1:3为了v = 1:3 arr = x(3 *(u-1)+1:3 *(u-1)+ 3,3 *(v-1)+1:3 *(v-1)+3 ,:);majorg(u,v,:) = sum(sum(arr,1),2)== a(1,1,9);结尾结尾sudpulzle.constraints.majorg = majorg;

通过在CLUE条目中设置1的下限来包括初始线索。此设置将相应条目的值修复为1,因此将每个矩值的解决方案设置为Clue条目。

为了U = 1:尺寸(b,1)x.lowerbound(b(u,1),b(u,2),b(u,3))= 1;结尾

解决数独谜题。

sudsoln =解决(sudpuzzle)
使用intlinprog解决问题。LP:最佳目标值为405.000000。找到最佳解决方案。intlinprog在根节点停止,因为客观值在最佳值的间隙容忍度范围内,Options.absolutegAppolerance = 0(默认值)。INTCON变量在容差,选项中是整数.inteGertolerance = 1E-05(默认值)。
sudsoln =.结构与字段:X:[9x9x9双]

围绕解决方案以确保所有条目都是整数,并显示解决方案。

sudsoln.x = round(sudsoln.x);y = y =(size(sudsoln.x));为了k = 2:9 y(:,:,k)= k;每个深度k%乘数k结尾s = sudsoln.x。* y;%通过其深度乘以每个条目s =总和(s,3);%s是9-by-9并保持求助的拼图drawsudoku

您可以轻松检查解决方案是否正确。

绘制sudoku拼图的功能

类型drawsudoku.
函数drawsudoku(b)%函数绘制Sumoku Board%2014 The Mathworks,Inc。图;保持ON;轴关闭;轴等%准备绘制矩形('位置',[0 0 9 9],'LineWidth',3,'剪切','关闭')%边框矩形('位置',[3,0,3,9],'LineWidth',2)%重垂直线矩形('位置',[0,3]那9.那3.],'LineWidth',2) % heavy horizontal lines rectangle('Position',[0,1,9,1],'LineWidth',1) % minor horizontal lines rectangle('Position',[0,4,9,1],'LineWidth',1) rectangle('Position',[0,7,9,1],'LineWidth',1) rectangle('Position',[1,0,1,9],'LineWidth',1) % minor vertical lines rectangle('Position',[4,0,1,9],'LineWidth',1) rectangle('Position',[7,0,1,9],'LineWidth',1) % Fill in the clues % % The rows of B are of the form (i,j,k) where i is the row counting from % the top, j is the column, and k is the clue. To place the entries in the % boxes, j is the horizontal distance, 10-i is the vertical distance, and % we subtract 0.5 to center the clue in the box. % % If B is a 9-by-9 matrix, convert it to 3 columns first if size(B,2) == 9 % 9 columns [SM,SN] = meshgrid(1:9); % make i,j entries B = [SN(:),SM(:),B(:)]; % i,j,k rows end for ii = 1:size(B,1) text(B(ii,2)-0.5,9.5-B(ii,1),num2str(B(ii,3))) end hold off end

相关话题