通过整数编程解决Sudoku难题:基于问题的
此示例显示了如何使用二进制整数编程来解决Sudoku拼图。对于基于求解器的方法,请参阅通过整数编程解决Sudoku难题:基于求解器。
您可能已经看到了Sudoku难题。一个难题是用1到9的整数填充9 x 9的网格,以便每个整数仅在每行,列和主要3 x 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难题以及许多程序化方法。此示例显示了使用二进制整数编程的直接方法。
这种方法特别简单,因为您不提供解决方案算法。只需表达Sudoku的规则,将线索表示为解决方案的约束,然后MATLAB产生解决方案。
二进制整数编程方法
关键的想法是将拼图从正方形的9 x-9网格转换为二进制值(0或1)的立方体9 x 9 x-9阵列。将立方阵列视为9平方网彼此堆叠的9平方网1.第二层在解决方案或线索中具有1个。2。第九层在解决方案或线索中具有9个。
该公式非常适合二进制整数编程。
这里不需要目标函数,也可能是一个恒定的项。问题实际上只是为了找到可行的解决方案,这意味着满足所有约束的解决方案。但是,要在整数编程求解器的内部中打破领带,从而提高了解决方案速度,请使用非稳定目标函数。
将Sudoku的规则表示为约束
假设一个解决方案 在9 x 9 x-9二进制阵列中表示。属性有什么作用 有?首先,2-D网格(I,J)中的每个正方形都有一个值,因此3-D数组条目中恰好有一个非零元素 。换句话说,每一个 和 ,,,,
同样,每行 在2-D网格中,每个数字从1到9中都有一个值。换句话说,每个数字 和 ,,,,
和每一列 在2-D网格中具有相同的属性:每个 和 ,,,,
主要的3乘3个网格具有相似的约束。对于网格元素 和 ,每个 ,,,,
要代表所有九个主要网格,只需向每个添加3或6个 和 指数:
在哪里
明确线索
每个初始值(线索)可以表示为约束。假设那个 线索是 对于一些 。然后 。约束 确保所有其他 为了 。
Sudoku在优化问题上
创建优化变量X
那是二进制的,大小为9乘9 x-9。
x = optimvar('X',9,9,9,'类型',,,,'整数',,,,“下界”,0,“上行”,1);
使用相当任意的目标函数创建优化问题。目标函数可以通过破坏问题的固有对称性来帮助求解器。
sudpuzzle = optimproblem;mul =一个(1,1,9);mul =暨(mul,3);sudpuzzle.Objective = sum(sum(sum(x,1),2)。*mul);
表示约束的总和X
在每个坐标方向上是一个。
sudpuzzle.constraints.consx = sum(x,1)== 1;sudpuzzle.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)==一个(1,1,9);结尾结尾sudpuzzle.constraints.majorg = majorg;
通过在线索条目下设置1个下限来包括初始线索。此设置将相应条目的值修复为1,因此将解决方案设置为每个线索值为线索条目。
为了u = 1:size(b,1)x.LowerBound(b(u,1),b(u,2),b(u,3))= 1;结尾
解决Sudoku难题。
sudsoln = solve(sudpuzzle)
使用IntlinProg解决问题。LP:最佳目标值为405.000000。找到最佳解决方案。IntlinProg停止在根节点上,因为目标值在最佳值的间隙公差之内。INTCON变量是公差,options.integertolerance = 1E-05(默认值)的整数。
sudsoln =带有字段的结构:X:[9x9x9 double]
围绕解决方案确保所有条目都是整数,并显示解决方案。
sudsoln.x = round(sudsoln.x);y =一个(size(sudsoln.x));为了k = 2:9 y(:,:,:,k)= k;每个深度k的乘数%结尾s = sudsoln.x。*y;%将每个条目乘以其深度s = sum(s,3);%s是9 x-9,并保留解决的难题绘制
您可以轻松检查解决方案是否正确。
功能绘制Sudoku难题
类型画
功能绘制用于绘制Sudoku Board%版权2014 Mathworks,Inc。的函数(B)%函数。,3,“剪辑”,“ off”)%在边界矩形外(“位置”,[3,0,3,9],“线宽”,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