用唯一法解数独(附 Matlab 代码)
最编程
2024-06-01 19:42:14
...
求解数独的算法有很多,比较暴力的有使用计算机依次检索所有空格,这种方法执行较慢,甚至出现内存溢出,基于此,有很多优化算法提出。本文是基于唯一法求解的。基本思路是将每一个格子的候选数求出来,然后将只有一个候选数的格子填上去,重复进行直到格子全满。流程如下图所示。数独的原始数据保存在excel文件中。如下图所示:
其中0表示空格子。这样的话,就可以将此表以矩阵的形式导入matlab。
具体算法:
此程序共有四个部分组成。分别是主程序,行列重复判断,宫重复判断以及候选数获取。
首先是最重要的候选数获取模块,其代码如下:
function [J,a]=suiji(J)
aa=(J==0);
a=sum(aa(:));%空格的个数
%获得空格坐标
X=zeros(a,2);
o=1;
for i=1:9
for j=1:9
if aa(i,j)==1
X(o,1)=i;
X(o,2)=j;
J(i,j)=0;
o=o+1;
end
end
end
%将数独分成9个3*3小块
JS=zeros(3,3,9);
i=1;
while(i<=9)
for p=1:3:7
for j=1:3:7
JS(:,:,i)=J(p:p+2,j:j+2);
i=i+1;
end
end
end
%找出每个空格可能的值
restore=zeros(47,9);
for i=1:a
q=1;
for m=1:9
re1=hl(m,X(i,:),J);%判断是否行列重复
re2=gong(m,X(i,:),JS);%判断是否九宫重复
if re1+re2==0
restore(i,q)=m;
q=q+1;
end
end
end
for i=1:a
if restore(i,2)==0
J(X(i,1),X(i,2))=restore(i,1);
end
end
end
其次是行列重复判断模块:
function [re1]=hl(m,zb,J)
reh=ismember(m,J(zb(1,1),:));
rel=ismember(m,J(:,zb(1,2)));
if reh+rel==0
re1=0;
else re1=1;
end
end
宫重复判断模块:
function [re2]=gong(v,zb,JS)
%寻找该值属于哪个宫
if zb(1,1)<=3
if zb(1,2)<=3
s=1;
elseif zb(1,2)<=6
s=2;
elseif zb(1,2)<=9
s=3;
end
elseif zb(1,1)<=6
if zb(1,2)<=3
s=4;
elseif zb(1,2)<=6
s=5;
elseif zb(1,2)<=9
s=6;
end
elseif zb(1,1)<=9
if zb(1,2)<=3
s=7;
elseif zb(1,2)<=6
s=8;
elseif zb(1,2)<=9
s=9;
end
end
re2=ismember(v,JS(:,:,s));%判断该值是否在宫里
end
最后是主程序:
clc
clear
J=xlsread('C:\Users\14418\Desktop\数独.xlsx');
aa=(J==0);
a=sum(aa(:));%空格的个数
while(a~=0)
[J,a]=suiji(J);
end
xlswrite('C:\Users\14418\Desktop\数独答案.xlsx',J)
使用matlab时要注意函数文件的命名方式,最后的输出是excel表格,如下图所示:
经过测试,本算法能够很快的计算出结果,并且结果完全正确。
注:本次实验仅仅是个人猜想,没有相关理论支撑,有个疑问就是为什么数独空白格子里必定至少有一个格子只有一个候选数,希望有大佬能解答下。
推荐阅读