数学建模最终论文c题.docx
《数学建模最终论文c题.docx》由会员分享,可在线阅读,更多相关《数学建模最终论文c题.docx(23页珍藏版)》请在冰豆网上搜索。
![数学建模最终论文c题.docx](https://file1.bdocx.com/fileroot1/2023-1/9/522277bd-4a82-4fec-9723-dc18c5d73118/522277bd-4a82-4fec-9723-dc18c5d731181.gif)
数学建模最终论文c题
Kakuro数独模型的建立
求解模型包括三个重要的子模型
1:
建立一个数学模型对kakuro中可能出现的和数进行所有可能的拆分;
2:
建立一个数学模型对一个已知的kakuro求解;
3:
产生有唯一解的kakuro;
由于第二步对kakuro的求解采用面向对象的工具软件,所以第二步和第一步是相互独立的。
在第三步的产生过程中,我们只是粗略地考虑了如何产生不同等级的kakuro和保证kakuro有唯一解。
对等级的划分我们还另外进行了讨论。
在第三步模型的建立中要用到第一个和第二个模型。
一.对Kakuro数独进行求解
1.通解方法--人工试探法
现在我们必须做的第一件事是考虑怎样解决Kakuro。
我们现在使用逻辑推理法和一点数学来解决题目要求的数模题,这里应用的方法将会被应用到我们产生kakuro的模型中。
根据以下方法可以确保最终得到数独的解,而且通过手工运算的时间基本可以控制在2个小时,不论难易程度,所以此方法可以作为取得数独答案的一般解法。
1、要解题,可以很快就看到提示的线索组合。
以右图为例,注意左下侧的空格组里,有一个提示码4(由上往下的加总)以及提示码3(向右的加总),两回交叠的区块里标有一个“A”。
2、只有1、2相加能得到3,1、3相加得到4,所以“A”只能是1、2、3其中一个数字。
但是,如果放3,提示码3那一列,就会得出一个不可能的组合,即3、0,如果放2,提示码4的那一列则会变成2、2相加,也算犯规。
所以“A”只可能是“1”。
(该情况出现的可能往往不多,除了较简单的数独题,但这是一个必要的过程,而且在随后的过程中要反复使用此方法。
)
依照这样的逻辑推论,如果“A”等于1,它上面的空格就是3(因为1+3=4),而它右边的空格就会是2。
2上方的两个空格依此逻辑解出。
相同道理,右上侧的空格组里,提示码3(由上往下加总)及提示码4(向右的加总),两回交叠的区块里标有一个“B”。
跟step2的判断方式一样,所以“B”只能是“1”。
依照这样的逻辑推论,如果“B”长等于1,它下面的空格就是2(因为1+2=3),而它左边的空格就会是3。
3下方的空格依此逻辑解出。
解开其余的谜底,就只需要简单的数字运算而已.
3、审视各个横列、竖列及根据其和罗列出的可能的数字结果,若发现某一个数字在各个横列、竖列出现的次数仅一次,则可以确定该空格的解为此数字。
并根据第二条的方法排除与此空格相关列或方格中相同的数字。
4、审视各个横列、竖列中罗列的各个可能的结果,找出相对称的两个数组合的空格(或3个、4个及其以上个数的组合),并确定这两个空格(或3个、4个及其以上个数的组合)的数字只可能为这两个数字,即两个数字在这两个空格的位置可以交换,但不可能到该行、该列的其他位置。
根据此结果可以排除相关列罗列出相关数字的可能,并缩小范围。
(该步骤处理的难度相对复杂,需要在积累一定经验的基础上进行,也是最终求解的关键)
5、反复使用2、3、4提到的步骤,逐步得到一个一个空格的解,并将先前罗列的各种可能的结果一个一个排除,使可能的范围越来越小,直至得到最后结果。
2.通过数学软件求解,建立数独问题的数学模型
现在以8×10的数独图为例介绍。
程序输入,一个8×10的输入矩阵.
算法的主要思想如下:
首先将线索格里的数据进行拆分;接着根据被拆分的数被”回”限制的个数,选出合适的组合;然后据此确定出可以确定的数;再尽量减少未定格子的变量,试探,回溯,最终求解。
为了随时调用线索格里的提示码的分解组合,对于8×10的数独,其每行每列数的和均小于45而大于3,建立一C语言程序将其可能的组合全部求出.
其源程序如下:
#include
#include
longres[1024];
voidfen(longn,longm)//n是需要拆分的数,m是拆分的个数。
{
longrest;
inti,j;
for(i=1;i<=n;i++)//从1开始尝试拆分。
{
if(i>res[m-1])//拆分的数大于前一个,保证不重复。
(第一个是0,虚拟的,不计入结果)
{
res[m]=i;;//将这个数计入结果中。
rest=n-i;//剩下的数是n-i。
if(rest==0&&m>1)//如果已经没有剩下的了,并且进度(总的拆分个数)大于1,说明已经得到一个结果。
{
for(j=1;j<=m;j++)
{if(res[m]<10.0)
printf("%ld",res[j]);
}
printf("\n");
}
else
{
fen(rest,m+1);//否则将剩下的数进行进度为m+1拆分。
}
res[m]=0;//取消本次结果,进行下一次拆分。
}
}
}
intmain()
{
longn;
printf("Inputn:
");
scanf("%ld",&n);
while(n>0.1&&n<45.1)
{memset(res,0,sizeof(res));
Total=0;
fen(n,1);
return0;}
}
}
运行这个程序,可以得出3~45之间的整数拆分结果。
其结果如下(其中前面表示被拆分的数,后面的表明差分结果。
由于拆分的结果必须在1~9之间,故写在一起的几位数为一种拆分结果.):
312
413
51423
61524123
7162534124
8172635125134
918273645126135234
10192837461271361452351234
11293847561281371462362451235
1239485712913814715623724634512361245
13495867,139148157238247256346123712461345
14596814915816723924825734735612381247125613462345
15697815916824925826734835745612391248125713471356234612345
16791691782592683493583674571249125812671348135714562347235612346
17891792692783593684584671259126813491358136714572348235724561234712356
1818927936937845946856712691278135913681458146723492358236724573456123481235712456
19289379469478568127913691378145914681567235923682458246734571234912358123671245713456
20389479569578128913791469147815682369237824592468256734583467123591236812458124671345723456
21489579678138914791569157823792469247825683459346835671236912378124591246812567134581346723457123456
2258967914891579167823892479256925783469347835684567123791246912478125681345913468135672345823467123457
23689158916792489257926783479356935784568123891247912569125781346913478135681456723459123458123467
2478916892589267934893579367845694578124891257912678134791356913578145682346923478123459123468123567
25178926893589367945794678125891267913489135791367814569145782347923569235782456834567123469123478123568124567
26278936894589467956781268913589136791457914678234892357923678245692457834568123479123569123578124568134567
273789468956791278913689145891467915678235892367924579246783456934578123489123579123678124569124578134568234567
28478956891378914689156792368924589246792567834579346781235891236791245791246781345691345782345681234567
29578914789156892378924689256793458934679356781236891245891246791256781345791346782345692345781234568
30678915789247892568934689356794567812378912468912567913458913467913567823457923467812345691234578
31167892578934789356894567912478912568913468913567914567823458923467923567812345791234678
32267893578945689125789134789135689145679234689235679245678123458912346791235678
333678945789126789135789145689234789235689245679345678123468912356791245678
34467891367891457892357892456893456791234789123568912456791345678
355678914678923678924578934568912357891245689134********678
36156789246789345789123678912457891345689234567912345678
3725678934678912467891345789234568912345679
3835678912567891346789234578912345689
391356789234678912345789
401456789235678912346789
41245678912356789
42345678912456789
433456789
4423456789
45123456789
该部分视图保存于附录.
算法流程
(1)设置初始化的方案(给变量赋初值,读入已知数据等);
程序输入,一个8×10的输入矩阵,有数字的地方就是指定的数字(线索格的数字以0|0的形式输入),没有数字的地方,实格子输入为00,空格子为0。
(2)变换方式去试探,若全部试完则转(7);
(3)判断此法是否成功,不成功则转
(2);
(4)试探成功则前进一步再试探。
;
(5)正确方案还未找到则转
(2);
(6)已找到一种方案则记录;
(7)退回一步(回溯),若未退到头则转
(2);
(8)已退到头则结束;
算法应用举例:
1.我们建立一个由0和1组成的一维未知数数组(0代表该处数值已知或不可填,1代表数值已知)和一个每一个原胞内含1~9的另一个候选数数组
我们在这里使用两个一维的数组并且它的第一个元素为零。
第一个一维数组用来存放横向元素的和,第二个一维数组用来存放竖向元素的和。
然后我们用前面给出的算法对给定已知条件的kakuro求解,举个简单的例子。
举例简单的4*4例子:
我们先建立两个如下数组:
011111110;
01234567891234567891234567891234567891234567891234567891234567890;
还有两个和值数组(横向优先):
1->17,3->17,6->8;
1->23,2->16,3->3;
通过第二步的模型我们得到答案:
(对于模型的初始值我们可以手工输入)
089197260
2.求解原例题
对于本题,为了便于说明解题过程,故做以下编码:
ABCDEFGHIJ
12345678
由于4只能拆分为1和3,而7要拆成3个数只能为1,2和4,故对于(2,F)只能为1;这是直观观察的结果.
下面根据”回”的限制对题中部分数拆分为:
3=1+2,4=1+3,7=1+2+4,5=1+4=2+3,6=1+5=2+4=1+2+3,7=1+6=2+5=3+4=1+2+4,
10=1+2+3+4,11=1+2+3+5,13=4+9=5+8=6+7,15=6+9=7+8,16=1+2+3+4+6,21=1+2+3+4+5+6=4+8+9=5+7+9=+6+8+9,26=2+7+8+9=3+6+8+9=4+5+8+9=4+6+7+9=5+6+7+8,38=3+5+6+7+8+9.
对于(7,E),由于10=1+2+3+4,13=4+9=5+8=6+7,显然可得(7,E)为4,进而得(8,E)为9,(8,D)为6;另外据38=3+5+6+7+8+9,5=2+3,可以轻易得出(3,I)为3,进而得出(3,J)为2;再有3=1+2,16=1+2+3+4+6,38=3+5+6+7+8+9,对于必须拆为3个包含1或2,和其它两个数的17有:
17=1+7+9=2+6+9=2+7+8,综合可得出(7,H)为6,(7,I)为9,(7,G)为2,(6,G)为1.再结合其它,可初定解应为:
2
另外的空格,根据相应的分析和试探,也可以去除掉很多候选数据.如此反复,可以得出最终解为
2131
13564232
24854273
5678481
1682135
2134269
6916
关于算法复杂度的讨论:
因为采用回溯法,并在其中用了候选数法,当每次碰到矛盾的时候,都会重新返回,从开始空格子开始更改.若按最大化复杂度算,每个格子都有9个候选数,则计算机要重复的次数为9的N次方的和,N为大于等于1小于等于63的数.
二.数独难度等级的划分问题
方法一
∙1.在数学里面,我们常常接触到自由度的问题。
自由度(degreeoffreedom,df)在数学中能够自由取值的变量个数。
如有3个变量x、y、z,但x+y+z=18,因此其自由度等于2。
在统计学中,自由度指的是计算某一统计量时,取值不受限制的变量个数。
通常df=n-k。
其中n为样本含量,k为被限制的条件数或变量个数,或计算某一统计量时用到其它独立统计量的个数。
∙对于数独的等级问题,我认为这显然为一个自由度多少的问题。
试想,当我们去求解一个线性方程组的时候,我们能熟练地解决一个二维的方程组,而对一个三维,四维乃至五维的方程组的解法感到困难。
因此,我们可以从这个简单的问题中提取今天的等级划分的依据,即自由度的多少是决定数独问题的难易程度的依据。
∙首先,我认为数独问题其实是一个二维或者说三维的线性方程组的解法问题。
我们可以从数独中提取一个解法的一个通项式:
∙F(Xij)=1Xij+2Xij+3Xij+4Xij+5Xij+6Xij+7Xij+8Xij+9Xij
∙只不过这里的Xij只能取0或者1.在数独的空格里,假如某个空格还没有设值,我们可以觉得这个数为1,2,3,4,5,6,7,8,9当中的一个,并且这个格子和它邻近的格子的数满足着某个方程的解。
∙由此,我们有理由认为,对于数独,它的难易,其实是它的自由度的多少决定的。
我们通过对下面几个例子来说明自由度对一个数独问题的影响。
∙在这里,我们觉得有必要把讨论一个数独问题的自由度的方法做一下说明。
首先,我们可以根据我们做过的问题的经验,对一个数独先进行分析一下,以确定那些可以确定的数值。
这些值的自由度,毫无疑问,可以确定为1,因为它只有这一种选择.而对于那些经过分析的格子,我们可以确定部分可能的解。
这些解,就是这个格子的自由度。
然后,对于这些可能的解的数目,即单个各自的自由度进行相乘(只是相对于未定值而言,当然确定值的自由度已经定义为1了)。
∙下面,我们根据即到例题,确定数独的自由度,进而对他进行级别的确定。
(注意,这里我们对各个格子的数的记法和我们在先前做的相同)。
∙
∙(a)
∙对这个题进行初步分析后,我们可以得到几个确定的值,比如(2,I)=2,(2,J)=9,(3,H)=3,(3,I)=1,(3,J)=2,(5,I)=9,(5,J)=7,(6,J)=1,等等。
∙下来我们来确定自由度。
∙对于(2,F),因为5=1+4=2+3,6=1+5=2+4,6的拆分数里面没有3,故(2,F)的自由度为3;但是这格并不是影响29的拆分数,故(2,G)的自由度为4。
再比如(7,E),由于7和35的拆分数均有1,2,4,鼓起自由度为3.因此我们可以总结求自由度的方法:
即确定的格子的自由度定为1,未定的各自的自由度四面看。
∙最后,我们可以定出此数独的自由度为
∙2^10*3^6*4^5*5^2*6^4*8^3*9^6
∙这是几乎天文数字。
因此这只是一种鉴别方法。
∙2.当然,我们也可以利用线性代数里面的一些内容。
重新对数独的难易问题进行分析。
我们可以根据未知数的多少来确定。
因为在这些方程里面,虽然能列出的方程不足以解决所有的解,但是,这些方程里面隐藏了很多的约束条件。
这是数独存在唯一解的原因。
当然,这里面还隐藏着格子数必须为1~9的整数这个条件了。
∙仍以上题为例,说明此法的可行性。
∙由题已知,空格子为46个,即可设的未知数为46个,变量可以为Xij表示。
在这46个变量里,有27个方程可以列出来。
显然,在这里面隐藏很多约束条件。
如必须为1~9的整数,如同行的数不相等,同列的数不相等。
∙我们假设,数独应该有解,在可能的情况下,我们可以解出少于27个数,但是剩下的大于19个数的未知数只能用这较少的变量来表示出来。
这一点可以从线性代数的理论获得解答。
因此,我们可以据此来确定等级。
注意,这里的等级并不一定表明它的难易程度,可能有些偏差。
具体操作如下:
∙因为这27个未知数有可能全解出来,我们就取这个最大的可能,即取方程数用n表示这个数目。
.另外,未知数也是要考虑的因素,用n表示。
又因为方程越多,越利于求解方程。
未知数越少,越利于求解。
故我们定义一个变量:
∙f=n/m.
∙那么g=1-f=1-n/m即可定义为难度系数:
∙当g>0.4时,数独为难;
∙当0.4>g>0.3时,数独难易程度为中:
∙当g<0.3时,数独为易。
∙对于上面的a题,我们可以轻易得出n=27,m=46,得出g=0.413,即此题为难;
∙同样,我们可以从下面的b题中,得出n=28,m=44,进而得g=0.364,此题难度适中。
∙
∙同样,在c题中,我们可以得出n=29,m=41,g=0.293,应该较易。
方法二
以8×10的Kakuro数独问题为例说明,在解数独题的时候,往往给
的数据越多,连续的空格数越少,给出的线索格的数字越小,在保证有解的
况下,就越简单。
一般情况下,只要连续的空格数小(即“回”比较小),就会使得给出的
字比较多且较小。
所以我们用连续格子的数目,来划分其难易级别。
现在我们规定权重因子N,难度系数A,空格数M,对行来说,M最大为9,对列来说M最大为7.
当M=9,N=20;
M=8,N=16;
M=7,N=12;
M=6,N=9;
M=5,N=7;
M=4,N=5;
M=3,N=2;
M=2,N=1;
则最大难度为A=7×20+9×12=248;
最小难度为0(此时所有格子都是实格子,为特殊情况了)
权重因子的选定条件及其原因:
N并不成等差数列,不成直线,而是斜率越来越大.
这是因为,考虑其边界条件,M较大时其出现的几率较小,而难度较大.而权重因子N的确定并非唯一,只是按其比率给定而已.并结合经验将其分级.
一般情况下,难度都集中在40到110之间,所以我们可以将难度划分为5个等级,5级,4级,3级,2级,1级,依次难度减小。
划分标准为:
当A>80时,为5级;
A>70时,为4级;
A>60时,为3级;
A>50时,为2级;
A<50时,为1级;
如下等级为五级A=96;
如下等级为4级:
A=76
如下等级为3级:
A=68
如下等级为2级:
A=52
如下为1级:
A=41
本文只给出简单的划分方式,因为数独算法复杂,判据并不唯一,.而更多的数独网站是采用人工解题时要用的方法的难易程度而确定的,有的也综合了人工解题得到答案的时间.
引用题目来自欧泊颗网站.
三.数独的产生
方法一:
我们建立模型用来产生横竖相连的空白格子,即产生未知数数组。
这些空白格子(即数值为1的元素)必须满足以下几个条件:
1:
不超过九个元素;
2:
不少于两个元素;
3:
空白格子必须是相连的;
4:
空白格子不能包括上边和左边两个边;
这里要确保至少有一些空白格子在下边和右边的边上。
然后我们根据产生的未知数数组和第一步模型的计算结果结合起来产生和数数组。
然后综合起来产生我们需要的kakuro:
1:
产生未知数数组;
2:
产生和数数组;
3:
解这个kakuro;
4:
有解没有?
如果没解并且此步循环少于若干(30)次转到2,循环大于3