摘要
现如今数独游戏风靡全球,深受人们喜爱。其难度等级多样,求解数独难度等级较高的常常需要花费大量的时间和精力,因此我们试图用计算机来解决这一问题。
在问题一中,我们主要考虑空格数的多少以及空格自由度与数独难度等级的关系。由一定的案例分析得出数独题目的难度等级与空格数存在正比关系,接着我们考虑如果只是简单的按照空格的数目多少来划分数独题目的难易程度是不全面的,因此继续分析,得出空格自由度与数独的难度等级存在正比的关系,最后又以空格数和空格自由度综合分析进行验证,得出此数独等级为3级。[1] 空格自由度法模型如下:
在问题二中,我们运用穷举法分析大量可能情况,再用MATLAB编写程序得出此数独游戏的终盘。
在问题三中,我们运用了比较排除法、唯一解法和综合法来求解此数独游戏,最终选用综合法作为较优方法。[1]
在问题四中,我们用循环回溯法进行求解,使用MATLAB编写程序得出结果(见表8)。[1]
关键字:穷举法 比较排除法 唯一解法 循环回溯法 数独 空格数 空格自由度
一、问题背景
数独是一种数字解谜游戏,英文名叫Sudoku,前身为“九宫格”,当时
的算法比现在的更为复杂,要求纵向、横向、斜向上的三数之和等于15,而不只是数字的不能重复,儒家典籍《易经》中的“九宫图”也是来源于此。关于它的起源一直存有争议,有人认为最早起源于中国,也有人认为起源于瑞士。1970年由美国一家数学逻辑游戏杂志首先发表,名为Number。后在日本流行,于1984年把Sudoku取名为数独。数独全面考验做题者观察能力和逻辑推理能力,它的玩法逻辑简单,除了1到9的阿拉伯数字以外,不必用到任何东西,但数字的排列方式却又千变万化,不少教育者认为,数独是锻炼大脑的绝佳方式。它不仅具有很强的趣味性,也是一种对智慧和毅力的考验。
二、问题重述
芬兰一位数学家号称设计出全球最难的“数独游戏”,并刊登在报纸上,
让大家去挑战。这位数学家说,他相信只有“智慧最顶尖”的人才有可能破解这个 “数独之谜”。
所给数独游戏表格如下:
据介绍,目前,数独游戏难度的等级有一到五级,一是入门等级,五则比较难。不过这位数学家说,他所设计的数独游戏难度等级是十一,可以说是所有数独游戏中,难度最高的等级。
数独是根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫内的数字均含1-9,不重复。 每一道合格的数
独谜题都有且仅有唯一答案,推理方法也以此为基础,任何无解或多解的题目都是不合格的。
由此我们要解决以下问题: 问题一: 分析此数独的难度; 问题二: 用穷举算法求解数独;
问题三: 设计此数独求解的较优的算法;
问题四: 建立数独求解模型并给出此数独的答案。
三、问题分析
根据题中所给信息我们知道数独是一种数字解谜游戏,要求游戏者有很好的观察能力和逻辑推理能力。 针对问题一:
分析此数独难度,我们认为有两点因素:一、空格数的多少,二、空间自由度。因此我们采取例证法进行分析,根据空格数来划分等级,进行一定的数据分析求出空格率,进而得出难度系数与空格数的关系。数独的难度等级与行、列、宫格内的空格数存在着密切联系,所以数独难易程度还与空间自由度有关。数独的空格自由度,指除掉空格本身,空格所在行、列、九宫内的空格数总和。除此之外我们可以以玩家完成数独题目的时间来判定数独题目的难度。 针对问题二:
“穷举法”是指当一个问题有几种可能而一时难以判定时,把几种可能一一列举出来,然后逐一尝试,直到尝试结果与给定的条件和结论相符为止。这种方法一般在计算机中运用,因为计算机计算速度快,可以很快验证答案是否正确,所以我们就以此来分析所有可能情况得出最终结果。 针对问题三:
为了找出更好的数独解法,我们运用了三种方法来求解。分别是:比较排除法、唯一解法和综合法。分析比较,选出较优方案。 针对问题四:
我们选用循环回溯法进行分析求解,与问题三中所求结果对比,以此验证其准确性。
四、模型假设
1、假设每种数独游戏都存在一定的联系且相互之间的难易程度成一定的比例; 2、假设实验者水平相同,随着实验不断进行,完成数独题目熟练程度不会增加; 3、假设实验者数独时间与数独题目难度无关。
五、符号说明
N 数独的空格数目 F 所有空格的自由度的总和 S(i,j) 数独矩阵A(9*9)中i行j列的空格自由度 S(i) i行的空格数目 S(j) j行的空格数目 gi 除去同行同列的同一宫中的空格数 六、模型建立与求解
6.1问题一的求解
为了更好的区分难易程度我们将数独以空格数划分为五个等级,具体划分如下:
空格数的取值范围为0-81,以空格数来平均划分难度等级,将空格数平均分成5个类型,空格数的取值范围缩小到37-81。 划分等级如下表所示:
37-45 46-54 55-63 64-72 73-81 1级 2级 3级 4级 5级 以《数独》为例,我们得到一些数据。《数独》题目数为100道,表格行表
示空格的个数,列表示难度的级别,一星为最容易,二星为容易,三星为难,四星为最难。例如:表一的首格3表示,难度为一星,空格数为50的题目有3道。
表1 统计《数独》空格数与难度 50 51 52 53 56 57 58 总数 一星 3 1 4 25 46 25 二星 1 1 21 1 1 三星 四星 35 11 14 8 3 经过多次试验与分析,我们初步得到,随着空格数的增加,数独的难度系数也相应的增加。为进一步探讨数独的难易程度是否还与其他因素有关,我们对数独题目的统计表格进行处理,在同等难度上,将每种空格的题目个数除以该难度的总题目数,得到如下表格。
表2 计算《数独》空格率与难度
50 51 52 53 56 57 58 一星 0.75 0.25 二星 0.04 0.04 0.84 0.04 0.04 三星 四星 0.76 0.24 0.56 0.32 0.12 表格的数据用图表表示(图1),由图可以清晰看出,难度等级递增,空格数也不断增加。难度等级与空格数存在正比的关系。
图1 《数独》空格数与难度
经过我们的多次试验与分析,我们初步得到,随着空格数的增加,数独的难度系数也相应的增加,当然数独题目的难度等级与空格数存在正比关系。难度等级的增加,空格数总体趋势递增,不同难度等级的题目空格数也一样的情况。 6.1.2空格自由度与难度等级
数独题目的难度等级与空格数存在正比关系。难度等级的增加,空格数总体
趋势递增,不同难度等级的题目空格数也一样的情况。我们得出初步结论,简单按照空格的数目多少来划分数独题目的难易程度是不全面的。同样空格数的数独题目,空格数分布位置的不同对难度等级也造成影响。 注:格数是决定难度等级的因素,但不是唯一的因素。
表3 统计《数独-再露锋芒》空格数与难度
45 47 49 51 52 53 54 55 56 57 总数 1 1 2 1 一星 3 1 1 二星 三星 10 18 40 1 2 9 3 2 1 2 1 1 22 8 5 2 四星 五星 4 1 1 1 6 15 1 3 6 10 计算空格自由度的模型如下:
空格自由度的取值范围大,当数独题目全为0时,空格的数为 81,空间自由度为2106;数独题目只剩1个空格时,空格自由度为0。在[0,2106]的范围内平均划分,将难度级别划分为5个等级,空格自由度0-420难度等级为1;421-841为2;842-1262为3;1263-1683为4;1683-2106为5。这与实际题目的难度划分不一致。空格自由度划分的区间缩小到[700,1300],[700,820]为1级,[820,940]为2级,[940,1060]为3级,[1060,1180]为4级,[1080,1300]为5级(图2)。
图2 空格自由度难度模型
随机抽取数独书籍不同难度等级的题目,进行空格自由度的计算,验证空格自由度衡量数独题目的难度是否合理,首先抽取4道不同难度的数独题目,将题目转换为字符串,计算空格自由度,实验结果如下:
表4 实验数据
数独题目 空格自由度 820 880 1008 1054 难度 2 3 4 4 书难度 2 2 3 4 1 2 3 4 由实验结果看出空格自由度与数独的难度等级存在正比的关系,难度系数的划分合理,与书中的划分基本一致。
数独题目的难度等级由空格数与空格自由度综合决定,建立几何难度等级模型:
(1)以数独的空格数来划分,将空格数为横坐标X;
(2)将空格自由度的总和划分等级,将等级数设为纵坐标Y;
(3)根据(X,Y)判定难度。
将计算好的空格数和空格自由度划分等级,两者结合,便可得到数独题目的难度等级了。难度等级等级为A-I,A为最易,I为最难,随着字母变大,难度逐次增加。具体划分的数据如下:
图3 难度判定坐标 表5 难度系数划分依据 难度等级 A B C D E F G H I X+Y 2 3 4 5 6 7 8 9 10
为了测试难度等级划分的情况的准确程度,主要做了如下测试: (1)测试的数独题目,查找出自《数独》和《路途中的数独》资料
表6 测试题目
题号 1 2 3 4 5 数独题目字符串 难度 一星 二星 二星 三星 四星
(2)书籍中对数独难度等级的划分,并不一定合理,为了更准确区分难度等级,我们将的题目由3个人完成,计算每道数独题目完成需要的平均时间,完成时间越长,数独题目难度越大。测试结果如下:
表7 测试结果 Test result
题号 空格数 空格自由度 1 2 3 4 5 45 53 52 56 57 698 922 880 1008 1054 难度 书中难度 完成时间 是否相符 A E E G G 一星 16min23s 二星 18min29s 二星 17min28s 三星 20min39s 四星 29min57s 是 是 是 是 否 (3)实验结果表明,划分的难度与书中所划分的难度基本一致。以玩家完成数独题目的时间来判定数独题目的难度的话,那么此种划分难度等级的方法也合理。
6.2问题二的求解
6.2.1 MATLAB编程求解数独 “链式推导方法”解数独定义
所谓链式推导方法就是根据数独题中候选数的出现关系或分布规律来推导,形成一条或多条推导链,最后证明某个或某些候选数是真或是假的解数独题的方法。
现在能想到的链式推导方法有:
1、由A证明B为假(由一个格子的候选数假设推导证明另一个格子里的某个候选数是假的方法)
2、由A证明B为真(由一个格子的候选数假设证明另一个格子的某个候选数是真的方法)
3、由A证明A为假(由某个候选数推导而出现错误证明本身假设是错的方法) 4、与成名方法结合的链式推导 5、还有………
如何推导,先定义一下,所说的A、B、C……、a、b、c……等等,都是候选数在某格子位置的代号。箭头“-->”是“导致”或“因此”的意思;“=”是等于,“<>”是不等于的意思;A=1-->B=2-->C=3……的意思是:当A是1时,导致B等于2,B等于2因此C就等于3……,余下类推;A=1-->B<>1-->……的意思就是当A是1时,B就不是1,余类推;“同一单元”的概念是指同一行或同一列或同一九宫格。 6.3问题三的求解
由于数独规则要求每行、每列和每宫的数字不重复,所以已出现的数字可以排除掉同行、同列、同宫中的其他单元格内再填入该数字的可能性,以下我们用两个截图解释。
比较排除法流程图如下:
Y判断所在格是否为空 与所在小九宫格已知量比较,排除取值域与之重叠的值 n与所在小九宫格已知量比较,排除取值域与之重叠的值 下一格 与所在小九宫格已知量比较,排除取值域与之重叠的值 取值域可能值的个数=1 赋值 n 所有格完成 n Y 正确结果
排除法的模型优点是步步为营,谨慎小心,出错率不大。但其推算过程较复
杂,编程水平要求很高,所以不适合解答本题。
当某行已填数字的宫格达到8个,那么该行剩余宫格能填的数字就只剩下那个还没出现过的数字了,成为行唯一解。
当某列已填数字的宫格达到8个,那么该列剩余宫格能填的数字就只剩下那个还没出现过的数字了,成为列唯一解。
当某九宫格已填数字的宫格达到8个,那么该九宫格剩余宫格能填的数字就只剩下那个还没出现过的数字了,成为九宫格唯一解。 以下我们用一个例子来简单的介绍这种算法:
A行已经添入8个数字,A行只有数字3没有出现
过,所以A9=3,这是行唯一解
第1列已经添入8个数字,第1列只有数字5没
有出现过,所以E1=5,这是列唯一解
在A8所在九宫格区域已经添入8个数字,只有
数字9没有出现过,所以A8=9,这是九宫格唯一
解
唯一解法实施起来比较简单,但就是因为简单所以只能应用于较简单的数独游戏中或者是用于较难数独游戏题型中的最后阶段,所以唯一解法的模型也不适合解答本题。
我们借鉴了数独游戏算法中几种算法的思想,进行归纳最后定义为综合法,其算法的步骤如下:
1、将所有未确定的格子的可能性定义为0xFFFF(即所有数字都可能),可能数目为9。
2、寻找所有确定的格子A(可能数目为0),在所有与A同行、同列和同区域的未确定的格子的可能性中减去与A相同的可能性。例如:A确定为9,则与A同行、同列和同区域(区域标志相同)的未确定的格子的可能性与0xFEFF按位与(除去可能性9),并将其可能性数目减少。
在除去可能性的过程中如果发现某个格子B的可能性数目由1减小为0,说明B和A只能取相同的数字,这可能是题目本身无解引起,也肯能是由于步骤3中搜索方向不对引起的,可认为此方向的搜索无解,退出这一方向的搜索。定义这个检查为唯一性检查。
3、寻找所有未确定格子中可能性数目最少的格子M,如果M的可能性数目为1,则确定M:将M的可能性数目定义为0,并把确定数量加1,如果此时确定数量达到81,则报告找到解,否则,在所有与M同行、同列和同区域的未确定的格子的可能性中减去与M相同的可能性,并进行唯一性检查。然后重复步骤3。
如果M的可能性大于1,则把M假设为所有M的可能性,分多个方向进行搜索,在每一个搜索方向重复步骤3(这个可以用递归来实现)。 6.4问题四的求解
在比较排除法、唯一解法的基础上,我们对模型进行深化,提出了循环回溯模型。其回溯法求解数独步骤如下:
1)按下标sp由小到大的顺序逐个获取空白位置;
2)对空白位置sp试图填数,填数的规律为从1-9依次由小到大选择(有序); 3)若找到一个可以填入的数据,将数据填入数独[sp],并将sp入栈push否则转5);
4)获取下一个空白位置,若有空白位置则转2),否则转6);
5)因为check(sp)返回1),找不到合适数据填入该位置,进行回溯,即pop得到上一次填数的位置sp,重新对该位置试图填数,且为了递推的高效性,此时可以仅从当前sp存放的数字大于1开始试图填充,转3); 6)填数结束。
回溯法流程图如下:
判断a是否全部确定 是 否 是 a(i,j)是 否确定 否 第一个候选值给a(i,j) 更新a 是 是否 矛盾 否 是否是最后候选值 是 寻找下一点 结束循环,输出a
否 下一个候选值 回溯到上一点
模型的整个函数体在while(isempty 1(a))的循环体中,只有当a得所有点
全部确定下来后,该循环才终止。我们是从矩阵的第一个元素开始循环的,首先判断a(i,j)是否确定,如果确定,则判断下一个点,如果a(i,j)没有确定,则把a(i,j)的第一个候选值赋给它,并用firstsolve()更新a100次,如果出现矛盾,即isright(a)=0,则说明第一个候选值错误,此时要把下一个候选值赋值给a(i,j),由于不同的a(i,j)的候选值下标是不同的,为此,需要指针表达这种关系,于是我们定义了一个新的细胞数组t=cell(9,9),用t{i,j}表示a(i,j)的候选值下标,并用语句: for ii=1:9 for jj=1:9
t={ii,jj}=1; end end
把t{i,j}的值初始化为1,以后循环中依次加1即可。当a(i,j)的所有候选值都尝试过后依然出现矛盾(isright(a)=0),则应该回溯到上一点,让上一点取下一个候选值,同时让当前点清空。回溯的时候容易出现的问题是发生越界,最容易发生的越界的点为每一行的第一个点和矩阵的第一个点a(1,1),为解决回溯越界问题,我们用一系列的if else 语句进行约束: j=j-1
else if j==1 j=9; i==i-1
if i==0 i=9 end end
需要注意的是,程序回溯的是上一个未确定的点,而不是上一个点,因此,在回溯过程中需要进行判断上一点是否已经是确定的点。
如果a(i,j)确定下来了,则应继续寻找下一点,此时又遇到越界问题,容易越界的点是矩阵的最后一个点a(9,9)和每一行的最后一个点,我们依然用一系列的if else 语句进行限制: j=j+1;
if j==10 i=i+1; i=1;
if i==10&&j==10 i=1; j=1; end end
这样,通过循环回溯,直到所有的点都已经确定下来,结束程序,可得出正确的解。 如下表所示:
表8 数独游戏终盘结果 8 1 2 7 5 3 6 4 9 9 6 1 3 2 5 4 7 4 7 5 6 8 2 3 9 3 5 4 9 7 1 8 6 6 4 2 8 1 9 5 3 8 9 3 4 6 7 2 1 2 1 7 5 9 4 6 8 1 2 8 7 5 3 9 4 7 8 9 2 3 6 1 5 5 3 6 1 4 8 7 2 七、模型优缺点
7.1模型优点:
(1)难度等级模型引入空格自由度的概念,是模型的创新点; (2)模型对数独的难度的分类较为直观; (3)难度等级的模型可操作性强;
(4)难度模型计算的难度等级符合现实的等级划分。
7.2模型缺点:
(1)模型所划分难度等级的区域过大,在实际题目中,数独的空格数往往较为集中在20-40中,研究的范围较大,划分的难度等级准确性低,主观成分过强;
(2)实验数据分析过程中,默认数独书籍对难度等级的划分为合理,这个前提存在不准确的可能,因为书籍中的难度等级划分,可能渗入编者个人的主观意识,笔者在研究过程中,没有剔除该种可能,也存在着不足;
(3)模型建立忽视数独题目所提供的数字不同,导致数独题目难度不一致的可能。
参考文献
[1]刘彬,刘丹彤,王倩倩.数学软件(2)课程设计..2012-07-21 [2]MonkeyDove.数学建模与数学实验计算机模拟..2012-07-21
附录
针对问题二编写的Matlab程序: function initial A=zeros(9,9); %骨灰级
A(1,[1 2 6 8])=[2 4 5 8]; A(2,[1 3 5 8])=[8 9 3 5]; A(3,[7])=[3];
A(4,[3 6 8 9])=[4 9 1 5]; A(6,[1 2 4 7])=[3 9 8 2]; A(7,[3])=[1];
A(8,[2 5 7 9])=[2 9 7 3]; A(9,[2 4 8 9])=[3 7 6 2];
disp('the inital condition is : ')
A %显示初始值 main(A); load result
disp('the result is : ') A end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function main(A)
if isempty(find(A==0))==1 save result A return; end
[i,j,P]=findmp(A); if length(P)==0 return; else
for k=1:length(P) A(i,j)=P(k); main(A); end end end
%%%%%%%%%%%%%%%%%%%%%找出可能元素最小的格子及其可能元素 function [i,j,P]=findmp(A) temp=zeros(9,9); temp(A>0)=10; for row=1:9 for col=1:9
if A(row,col)==0
r=A(row,; r=r(r>0); c=A(:,col); c=c(c>0);
rc1=and_log(r,c);%行列不同元素放在rc中 rr=findrc(row); cc=findrc(col);
rc2=reshape(A(rr*3+1:rr*3+3,cc*3+1:cc*3+3),1,9); rc2=rc2(rc2>0);
total=and_log(rc1,rc2);
temp(row,col)=9-length(total); end end end
[v,i]=min(temp); [v,j]=min(v); i=i(j);
row=i;
col=j; %以下找出可能元素 r=A(row,; r=r(r>0); c=A(:,col); c=c(c>0); rc1=and_log(r,c); rr=findrc(row); cc=findrc(col);
rc2=reshape(A(rr*3+1:rr*3+3,cc*3+1:cc*3+3),1,9); rc2=rc2(rc2>0);
total=and_log(rc1,rc2); P=[];
for kkk=9:-1:1
if isempty(find(total==kkk))==1 P=[P,kkk]; end end end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%集合A&B求和 function c=and_log(a,b) c=a;
for i=1:length(b) log=0;
for j=1:length(a) if b(i)==a(j) log=1; break; end end
if log==0 c=[c,b(i)]; end end end
%%%%%%%%%%%%%%%%%%%找出九个小方格所在位置 function rr=findrc(row) switch row case {1 2 3} rr=0;
case {4 5 6} rr=1;
otherwise rr=2; end
针对问题四用matlab编写数独9*9的程序:
function y=choose1(a) y=cell(9,9);
choose=cell(9,9);
select=[1,2,3,4,5,6,7,8,9]; save=cell(9,9); grid=cell(3,3); templ=a (1:3,1:3);
grid{1,1}=temp1(temp1>0)’; temp2=a(1:3,4:6);
grid{1,2}=temp2(temp2>0)’; temp3=a(1:3,7:9);
grid{1,3}=temp3(temp3>0)’; temp4=a(4:6,1:3);
grid{2,1}=temp4(temp4>0)’; temp5=a(4:6,4:6);
grid{2,2}=temp5(temp5>0)’; temp6=a(4:6,7:9);
grid{2,3}=temp6(temp6>0)’; temp7=a(7:9,1:3);
grid{3,1}=temp7(temp7>0)’; temp8=a(7:9,4:6);
grid{3,2}=temp8(temo8>0)’; temp9=a(7:9,7:9);
grid{3,3}=temp9(temp9>0)’; %%%%%%%%%%%%%%%%%%%%
%求出每一点处所在行、列、九宫格处已有的点 for i=1:9 for i=1:9
if a(i,j)=0
n1=find(a(i,:>0); N1=a(I,n1);
n2=find(a(:,j)>0); N2=a(n2,j);
N2=N2’; aaa=[N1,N2];
%%%%%%%%%%%%%%%%%%%%
%把a(i,j)所在行、列、九宫格已确定的数字合并 if i>=1&&i<=j&&j<=3
aaa=[aaa,grid{1,1}];
else if i>=1&&i<=3&&j>=4&&j<=6 aaa=[aaa,grid{1,2}];
else if i>1&&i<=3&&j>=7&&j<=9 aaa=[aaa,grid{2,1}];
else if i>=4&&i<=6&&j>=4&&j<=6
aaa=[aaa,grid{2,2}];
else if i>=4&&i<=6&&j>=7&&j<=9 aaa=[aaa,grid{2,3}];
else if i>=7&&i<=9&&j>=1&&j<=3 aaa=[aaa,grid{3,1}];
else if i>=7&&i<=9&&j>=4&&j<=6 aaa=[aaa,grid{3,2}];
else if i>=7&&i<=9&&j>=7&&j<=9 aaa=[aaa,grid{3,3}]; end
end end end end end end end end
aaa=unique(aaa); save{i,j}=aaa; end
end
end
%%%%%%%%%%%%%%%%%%%% %求出每一处的候选数字 for i=1:9 for j=1:9 n=[];
if a(i,j)=0
choose{i,j}=a(i,j); else if a(i,j)=0 temp=select;
for t=1:length(save:{i,j})
n(t)=find(temp=save{i,j}(t)); temp(n(t))=[]; end
choose{i,j}=temp; end
end end end
y=choose;
%%%%%%%%%%%%%%%%%%%%
%找出一次性能确定的点,不用回溯
function y=firstsolve(a) choose2=choose1(a); a1=[]; for i=1:9 for j=1:9
if length(choose2{i,j})=1; a1(i,j)=choose2{i,j}; else contine end end end a=a1; y=a;
%%%%%%%%%%%%%%%%%%%%
%判断举证元素是否全部确定,如果确定,返回0,否则返回1 function y=isempty1(a) choose2=choose1(a); tempp=0; for i=1:9 for j=1:9
if length(choose2{i,j})>1||a(i,j)=0 tempp=1; end end end
y=tempp;
%%%%%%%%%%%%%%%%%%%%
%判断该矩阵的点是否有解,如果无解,则返回值为0,否则返回值为1 function y=isright(a) choose2=choose1(a); tempp=1; for i=1:9 for j=1:9
if length(choose1{i,j})==0 tempp=0; end end end
y=tempp;
%%%%%%%%%%%%%%%%%%%% function y=sudu_solve(a) i=1; j=1;
choose2=choose1(a); t=cell(9,9); for ii=1:9 for jj=1:9
t={ii,jj}=1; end end
while isempty1(a) if a(i,j)==0
while t{i,j}<=length(choose2{i,j}) a(i,j)=choose2{i,j}(t{i,j}); for isright(a)==1 break
else if isright(a)==0 t{i,j}=t{i,j}+1;
if t{i,j}>=length(choose2{i,j}) t{i,j}= length(choose2{i,j});
end
a(i,j)=choose2{i,j}(t{i,j}); end end end
%[][][][][][][][][][][][][][][][][][][][][][][][][][][][] if isright(a)==0 a(i,j)=0; if j>1 j=j-1; else if j==1 j=9; i=i-1; if i==0 i=9 end
end end
if length(choose2{i,j})==1 if j>1 j=j-1;
else if j==1 j=9; i=i-1; if i==0 i=9;
end
end end Else
%上一点的候选值改变,如果上一点的候选值只有一个,则继续寻找上一点 a(i,j)=choose2{i,j}(t{i,j}+1) end end
%跳出循环后继续寻找下一点 j=j+1; if j==10 i=i+1; j=1;
if i==10&&j==10 i=1; j=1; end end
%如果a(i,j)的值确定,寻找下一点 else
j=j+1; if j==10 i=i+1; j=1;
if i==10&&j==10 i=1; end end end end y=a;
%%%%%%%%%%%%%%%%%%%% function y=generate()
a=[ 8 1 2 7 5 3 6 4 9;
9 4 3 6 8 2 1 7 5; 6 7 5 4 9 1 2 8 3; 1 5 4 2 3 7 8 9 6; 3 6 9 8 4 5 7 2 1; 2 8 7 1 6 9 5 4 3; 5 2 1 9 7 4 3 6 8; 4 3 8 5 2 6 9 1 7; 7 9 6 3 1 8 4 5 2] select=a; count=0; while (1)
h=rand;
n=floor(53*h+64*(1-h)); a=reshape(a,1,81); NN=randperm(81);
%从a中随机选取n个数字,使其为空 for t=1:n
a(NN(t)=0; end
a=reshape(a,9,9); choose=choose1(a); for i=1:9 for j=1:9
if length(choose{i,j}>=3 count=count+1; end end end
if count>40 break else
a=select; end end y=a;
function y=generate()
a=[ 8 1 2 7 5 3 6 4 9;
9 4 3 6 8 2 1 7 5; 6 7 5 4 9 1 2 8 3; 1 5 4 2 3 7 8 9 6; 3 6 9 8 4 5 7 2 1; 2 8 7 1 6 9 5 4 3; 5 2 1 9 7 4 3 6 8; 4 3 8 5 2 6 9 1 7; 7 9 6 3 1 8 4 5 2]; %aa=sudu_solve(a) select=a; count=0; while (1) h=rand;
n=floor(30*h+40*(1-h)); a=reshape(a,1,81); NN=randperm(81);
%从a中随机选取n个数字,使其为空 for t=1:n
a(NN(t))=0; end
a=reshape(a,9,9); choose=choose1(a); for i=1:9 for j=1:9
if length(choose{i,j})==1 count=count+1; end end end
if count>40 break else
a=select; end end
%任取互换a中两个数字的位置 a=reshape(a,1,81); hh1=rand; hh2=rand;
h1=floor(hh1+9*(1-hh1)) h2=floor(hh2+9*(1-hh2)) if h1==h2 h1=1; h2=9; end
n1=find(a==h1); n2=find(a==h2); for i=1:length(n1) a(n1(i))=h2; end
for i=1:length(n2) a(n2(i))=h1; end
a=reshape(a,9,9); a=a’; y=a
因篇幅问题不能全部显示,请点此查看更多更全内容