埃及分数问题文档格式.docx
《埃及分数问题文档格式.docx》由会员分享,可在线阅读,更多相关《埃及分数问题文档格式.docx(7页珍藏版)》请在冰豆网上搜索。
【IDA*法】解析:
在进行本算法解析之前,我们先分析几个问题。
上面我们利用贪心法进行了求解,在贪心法逐步选择当前分数所包含的最大埃及分数时,是按照如下方法计算的,例如:
7/8内所包含的最大埃及分数是什么呢?
7/8包含最大埃及分数分母=8/7+1=2
7/8-1/2=3/8,查找3/8内的最大埃及分数如下:
3/8包含最大埃及分数分母=8/3+1=3
得到3/8-1/3=1/24,如今1/24差不多是埃及分数,那么不再进行计算,得到解7/8=1/2+1/3+1/24。
如此,我们总结得到每次当前被求解的分数的下界如下:
1/(当前分数的分母/当前分数的分子+1)
那么上界是什么呢?
在进行IDA*算法求解之前,我利用了一般的搜索技术进行了求解,下面先说明一般搜索算法的思想。
上面我们能够利用(分母/分子+1)的方法求得当前分数的下界,由于那个下界是当前分数内所包含的最大埃及分数,那么从当前分数内减掉那个最大埃及分数后,假设得到的一个分数还不是埃及分数,将进入下一层的计算(同样求得下界)。
那么那个下界一定是小于上一层的下界值的(缘故很简单,分数越减越小),而由于本问题求解的是分数问题,那么逐层下降的下界涉及到分数的分母上那么是递增的,例如:
7/8=1/2+1/3+1/24
其解的分母递增。
那么要保证其分母递增,其每次的减数那么不应超过被减数(即:
小于被减数),否那么得到的结果是降序的。
如此我们得到一个求解上界的方法,下面举例说明:
19/45-1/3=4/45,那么得到4/45为下界,那么上界是多少呢?
依照上面的分析结果,要保证升序那么减数应不超过被减数,而不超过19/45的减数是多少呢?
我们将19/45乘以1/2即可(例如:
被减数为5那么保证升序的结果时,最大减数为2,也确实是将5×
1/2-1)。
只是那个地方面还有一个小问题需要说明:
1.当分子是1时那么上界是:
1/(被减数分母×
2-1)
2.当分子非1时那么上界是:
被减数×
1/2(通过比较)
例如:
19/45-1/3=4/45,那么3×
2-1=5(即:
最小将1/3缩减至1/5,能够保证升序)
将1/3的分母逐步扩大如下:
19/45-1/4=31/180(31/180<1/5)
19/45-1/5=2/9(2/9>1/5)
19/45-1/6=23/90(23/90>1/5)
下面我们看一下后两种接着计算的结果:
19/45-1/5=2/9
2/9-1/5(本层下界)=1/45
从而得到一个解19/45=1/5+1/5+1/45,然而问题中不同意出现加数相同的解,故那个解是要被舍掉的。
再看一下另一个计算结果:
19/45-1/6=23/90
23/90×
1/4(本层下界)=1/180
从而得到一个解19/45=1/6+1/4+1/180,显然解中出现了降序的分母排列,那个解也要被舍掉(缘故是前面我们搜索的升序解时差不多出现了一个1/4+1/6+1/180,而题目中并未对每个加数的出现位置做规定,为了过滤掉重复出现的解,并减少搜索空间,故此我们只按照升序的方向进行搜索,如此就保证了不出现重复的解,及不出现加数重复的解,也可不能漏掉解)。
上面说明了当分子是1的情况。
当分子非1时,我们要将减数×
1/2,然后通过比较大小确定是否再进行深度搜索。
再看下面的例子:
首先19/45-1/3=4/45,然后求得4/45的下界是12,那么有4/45-1/12=1/180。
得到一个解:
那么以1/12为起点的下界的搜索上界是多少呢?
我们将4/45乘以1/2得到2/45,而那个2/45是要通过与每次的减数比较大小而确定是否接着进行深度搜索的(缘故是它是分数,且分子非1)。
而那个比较还要进行精确计算得到结果(不能用每个分数除得的结果草草比较,如此的比较属于C++中的浮点数比较,是比较忌讳的操作且不准确,可能会出现上界过小而漏掉解的情况)。
下面将1/12的分母逐步扩大如下:
4/45-1/13=7/585(7/585<2/45)
4/45-1/14=11/630(11/630<2/45)
4/45-1/15=1/45(1/45<2/45解)
4/45-1/16=19/720(19/720<2/45)
4/45-1/17=23/765(23/765<2/45)
4/45-1/18=1/30(1/30<2/45解)
4/45-1/19=31/855(31/855<2/45)
4/45-1/20=7/180(7/180<2/45)
4/45-1/21=13/315(13/315<2/45)
4/45-1/22=43/990(43/990<2/45)
4/45-1/23=47/1035(47/1035>2/45)
当分母增加到23时出现降序,这时我们能够确定不再向下层搜索,而是赶忙返回到上层搜索上层剩余未搜索完的部分。
那么如何进行分数的比较运算呢?
我们明白当两个分数进行相加、减时先要进行通分母的操作,然后才进行分子相加、减得到结果。
故设有A/B±
C/D那么有如下公式:
=
±
ACA×
D±
B×
C
BDB×
D
通过观看上面公式我们得到当进行减法计算时,一旦出现分子为负数的情况,那么说明被减数小于减数,如此通过上述公式进行计算那么得到的结果是精确判断。
至此,关于分子是1与分子非1的情况阐述完毕。
下面我们以19/45为例,详细说明一下求解过程:
首先,19/45内所包含的最大埃及分数是1/3,那么用19/45-1/3=4/45(以1/3为下界,而上界为1/5,本层为1层),而4/45还不是埃及分数,接着找到4/45内所包含的最大埃及分数是1/12(以1/12为下界,以2/45为上界比较点进行比较,本层为2层),那么有4/45-1/12=1/180。
得到一个解为:
19/45=1/3+1/12+1/180。
返回到2层,扩大减数分母为13,那么有4/45-1/13=7/585,而7/585还不是埃及分数,但如今假如接着向下搜索的话,其最终结果至少大于已得到的一个解的加数个数3,因此不必接着向下层搜索(那个地方称为越界,下同)。
而是接着第2层未计算完的部分。
扩大减数分母为14,那么有4/45-1/14=11/630(越界)。
接着有4/45-1/15=1/45。
19/45=1/3+1/15+1/45。
返回2层,扩大分母至16,有4/45-1/16=19/720(越界)。
接着扩大至17,那么4/45-1/17=23/765(越界)。
接着扩大至18,那么4/45-1/18=1/30。
19/45=1/3+1/18+1/30。
返回2层,有4/45-1/19=13/855(越界)。
接着扩大至20,那么4/45-1/20=7/180(越界)。
接着扩大至21,那么4/45-1/21=13/315(越界)。
接着扩大至22,那么4/45-1/22=43/990(越界)。
接着扩大至23,而如今通过比较有2/45>1/23(已超过2层上界),返回到1层。
将1/3的分母3扩大至4,那么有19/45-1/4=31/180,接着搜索进入2层,找到31/180包含的最大埃及分数是1/6,那么31/180-1/6=1/180(下界1/6,上界以31/360比较)。
19/45=1/4+1/6+1/180。
返回2层,扩大分母为7有31/180-1/7=37/1260(越界)。
接着扩大至8,那么31/180-1/8=17/360(越界)。
接着扩大至9,那么31/180-1/9=11/180(越界)。
接着扩大至10,那么31/180-1/10=13/180(越界)。
接着扩大至11,那么31/180-1/11=161/1980(越界)。
接着扩大至12,如今通过比较有31/360>1/12(已超过2层上界),返回到1层。
将1层的分母4扩大至5,那么有19/45-1/5=2/9,接着搜索进入2层,找到2/9包含的最大埃及分数是1/5,那么2/9-1/5=1/5(下界1/5,上界以1/9比较)。
如今,尽管得到了一个解,然而解中出现相同加数,那么放弃那个解,返回2层将扩大分母5至6,那么有2/9-1/6=1/18。
19/45=1/5+1/6+1/18。
返回2层,扩大分母为7那么有2/9-1/7=5/63(越界)。
接着扩大至8,那么2/9-1/8=7/72(越界)。
接着扩大至9,如今的1/9与上界相同,那么放弃搜索(即:
到达上界),返回1层,而1层的分母也差不多到达上界5,算法结束。
最终找到5个解,其最正确表示法是19/45=1/5+1/6+1/18,那个地方能够通过比较最后一个加数的分母大小求得(因为我们是按照升序搜索的,故最后一个加数一定是最小的一个,那么按照题目要求就比较它的分母即可)。
上面确实是一般搜索算法的求解思想及过程(在那个算法中一并使用高精度计算求解),尽管在算法中计算了上下界(通过上下界进行了范围界定),然而当出现类似998/999、13/997的分数进行求解时,会由于其每层的上下界之差过大,而反复调用高精度计算进行增量、加、乘等操作。
而关于高精度计算我们不可幸免的要使用字符串数组存储计算结果,而埃及分数算法中又要涉及到反复的递归计算,如此就不可幸免的在每次进入递归口时要使用动态分配字符串空间(即:
调用’堆’空间),而在如上的尖端分数其上下界过大时,又要反复进行递归、返回操作,这就不断的在消耗’堆’资源(‘堆’空间不象’栈’空间,它只能在整个算法结束后才释放分配的空间,而’栈’是随时释放的,算法未结束时下次还能够使用。
这就导致了’堆’被分配后不能被重复利用),最终算法没有结束,而’堆’空间被耗尽导致算法崩溃(即便将高精度计算中用到的动态分配空间统一提出来作为公共数组使用,那么也不能满足计算0<a<b<1000范围内的埃及分数求解,最终放弃一般搜索方法的代码编制)。
以上是对一般搜索算法的分析。
那么要满足题目要求的计算范围内求解埃及分数,该采纳什么方法呢?
下面我们就来探讨IDA*算法进行求解的原理。
所谓IDA*算法确实是基于迭代加深的A*算法。
算法以试探性的递归深度进行搜索,假如当前的试探搜索深度找到了解,那么算法在本次搜索深度完毕后结束,否那么就增加一层搜索深度进行搜索,直到找到解并结束于本次搜索深度。
下面详细讲解IDA*算法的求解过程:
M=19、N=45
开始在Search_IDA函数中置parts=1,found=0。
进入while()循环,由于还没有找到解,那么将parts加1,表示将以2层的搜索深度进行搜索(注:
假如1层出现解,那么可不能进入到while循环)。
接下来进入Decomposition(m,n,Deep)函数(以下简称D()函数)。
D(19,45,2)
计算得到min=3,而max如何计算呢?
前面的一般搜索算法我们讲过计算下界时,以分母/分子+1的方式计算,而计算上界时以不超过本层分数的一半为上界(注:
通过计算后的值比较参考是否返回上层)。
那么假如如今在IDA*算法中同样用此方法的话,就回出现大量重复的计算(前提是在操纵递归深度的同时),故此我们用一种新的方法计算出上界,此方法计算出的上界操纵了搜索范围(那个范围是配合当前的递归深度进行的),并减少了大量重复的搜索。
那么如何计算呢?
我们同样以分母/分子求得一个数,由于要配合递归深度,那么我们将那个计算结果乘以递归深度,便可得到其上界值(注:
关于代码中的max部分的判断操作,见下面的解析。
关于分母/分子×
Deep的计算,为了尽量保证计算精度,我们应采取以Deep×
分母/分子的形式求得)。
下面返回讲解处,求得max=4,那么本层的上下界为[3,4]。
置Temp[1]=3后进入下一层D(12,135,1),由于转到下一层后其分子不为1,那么返回到本层。
置Temp[1]=4后进入下一层D(31,180,1)同样其分子不为1,返回本层。
这时本层已到达下界4,退回到Search_IDA()函数中将parts增加为3层搜索深度后重新进入D()函数。
(注:
在此假如我们按照一般搜索技术的方法求得的上界是5,那么如今就要多计算1次以5为第一层的搜索,同样得不到解)。
D(19,45,3)
计算本层上下界[3,7],Temp[2]=3,进入2层D(12,135,2),计算上下界[12,22],Temp[1]=12,进入3层D(3,540,1),可知n/m为1,Temp[0]=180得到一个解:
3、12、180,found=1。
返回到2层Temp[1]=13,进入3层D(7,585,1)本次分子不为1返回2层。
Temp[1]=14,进入3层D(11,630,1)本次分子不为1返回2层。
Temp[1]=15,进入3层D(15,675,1)得到15整除675为45,Temp[0]=45得到解3、15、45,比较解的最后一项45<180,那么更新最优解为:
3、15、45。
返回2层Temp[1]=16,进入3层D(19,720,1)分子不为1返回2层。
Temp[1]=17进入3层D(23,765,1)分子不为1返回2层。
Temp[1]=18进入3层D(27,810,1)27整除810为30得到解:
3、18、30,比较末项30<45,更新最优解为:
3、18、30。
返回2层。
Temp[1]=19进入3层D(31,855,1)分子不为1返回2层。
Temp[1]=20进入3层D(35,900,1)分子不为1返回2层。
Temp[1]=21进入3层D(39,945,1)分子不为1
Temp[1]=22进入3层D(43,990,1)分子不为1
如今2层到达搜索上界,返回1层Temp[2]=4进入2层D(31,180,2)计算上下界[6,11],Temp[1]=6进入3
层D(6,1080,1)得到6整除1080为180,Temp[0]=180得到解4、6、180,比较解的最后一项180>45,那么放弃当前解。
返回2层,Temp[1]=7进入3层D(37,1260,1)分子不为1返回2层。
Temp[1]=8进入3层D(68,1440,1)分子不为1返回2层。
Temp[1]=9进入3层D(99,1620,1)分子不为1返回2层。
Temp[1]=10进入3层D(130,1800,1)分子不为1返回2层。
Temp[1]=11进入3层D(161,1980,1)分子不为1返回2层。
如今2层到达搜索上界,返回1层Temp[2]=5进入2层D(50,225,2)计算min=225/50+1=5,而通过判断Deep<parts&
&
Temp[Deep]+1>min成立,这表示当前Deep层被搜索的数非第一层(即:
不是第一项值),且差不多存储于Temp中的第一项值与此值相等(如:
Temp[2]=5,而刚刚计算的min=5,那么假如按照当前层最小值为5进行搜索的话,就会出现将Temp[1]置为5那么重复出现两个5,违反题意。
假如当小于此值时还会出现逆序分母的情况)。
故遇到此种情况那么将本此下界min改为Temp[2]+1即可。
最终计算上下界为[6,8],Temp[1]=6进入3层D(3,54,1)得到3整除54为18,Temp[0]=18得到解5、6、18,比较解的最后一项18<30,那么更新最优解为:
5、6、18。
返2层,Temp[1]=7进入3层D(5,63,1)分子不为1返回2层。
Temp[1]=8进入3层D(7,72,1)分子不为1返回2层。
如今2层到达搜索上界,返回1层。
Temp[2]=6进入2层D(69,270,2),计算上下界为[7,7],Temp[1]=7进入3层D(71,630,1)分子不为1,返回2层,2层到达搜索上界,返回1层。
Temp[2]=7,进入2层D(88,315,2)计算min=4,改变min为Temp[2]+1=8(否那么出现逆序与重复),max=7,由于min>max直截了当返回1层,如今1层到达搜索上界,算法结束。
最终被保留的最正确埃及分数表示法为:
关于max的计算问题,按照上面一般搜索技术的方法,第一层最多max为5,当大于5时将出现逆序分母。
而本算法当按照3层深度搜索时,计算第一层的max为7,这与一般搜索技术的方法略有出入,然而它并不妨碍计算结果,且很快就可判断并返回到上层函数中。
而关于max部分的判断操作参见下面:
当首层Temp[2]=5时,进入第2层D(2,9,2),如今计算max=9(判断部分为Deep×
n/m=0),而通过对上面讲述的一般搜索方法的求解过程得知,当本层下界为9时,将出现重复分母问题(即:
1/5+1/9+1/9)。
故将max减1去掉那个出现重复分母的下界值(即:
max判断部分的用途)。
至此,IDA*算法计算埃及分数的过程讲解完毕。
总结:
关于埃及分数这类问题,能够由任意的分数凑成,而关于加数个数(如:
19/45中的三个加数),也能够有不同大小的分数构成。
因此其状态空间是无穷大的,深度搜索的话,就会出现无限递归而没有返回的情况。
广度搜索的话,其空间消耗不起。
而ID(iterativedeepening)的实质确实是:
使用深搜的框架来写宽搜(即:
在dfs搜索算法的基础上逐步加大搜索的深度,它幸免了广度优先搜索占用搜索空间太大的缺点,也减少了深度优先搜索的盲目性。
那么,总要牺牲一点东西,确实是时间,每次加深的工作量是重复的。
然而那个重复的工作量,由于搜索的状态空间为指数级增长,能够不记。
IDA*算法要紧是在递归搜索函数的开头判断当前搜索的深度是否大于预定义的最大搜索深度,假如大于,就退出这一层的搜索,假如不大于,就接着进行搜索。
如此最终获得的解必定是最优解。
而在A*算法中,我们通过使用合理的估价函数,然后在获得的子节点中选择fCost最小的节点进行扩展,以此完成搜索最优解的目的。
然而A*算法中,需要维护关闭列表和开放列表,需要对扩展出来的节点进行检测,忽略差不多进入到关闭列表中的节点(也确实是所谓的”差不多检测过的节点”),另外也要检测是否与待扩展的节点重复,假如重复那么进行相应的更新操作。
因此A*算法要紧的代价花在了状态检测和选择代价最小节点的排序上,那个过程中占用的内存是比较大的,一般为了提高效率基本上使用hash进行重复状态检测。
IDA*算法综合了A*算法的人工智能性和回溯法对空间消耗较少的优点,在一些规模很大的搜索问题中会起意想不到的效果。
它的具体名称是IterativeDeepeningA*,1985年由Korf提出。
该算法的最初目的是为了利用深度搜索的优势解决广度A*的空间问题,其代价是会产生重复搜索。
归纳一下IDA*的差不多思路:
首先将初始状态结点的H值设为阈值maxH,然后进行深度优先搜索,搜索过程中忽略所有H值大于maxH的结点;
假如没有找到解,那么加大阈值maxH,再重复上述搜索,直到找到一个解。
在保证H值的计算满足A*算法的要求下,能够证明找到的那个解一定是最优解。
在程序实现上,IDA*要比A*方便,因为不需要保存结点,不需要判重复,也不需要依照H值对结点排序,占用空间小。
在IDA*算法中也要使用合适的估价函数来评估与目标状态的距离。
在一般的问题中是如此使用IDA*算法的:
当前局面的估价函数值+当前的搜索深度>预定义的最大搜索深度就进行剪枝。
那个估价函数的选取没有统一的标准,找到合适的该函数并不容易(例如:
上述IDA*算法在计算max值时可能会出现不准确的情况),然而能够大致按照那个原那么在一定范围内加大各个状态启发函数值的差别。
【注:
关于IDA*算法求解埃及分数时,同样不能用高精度计算,因为它同样会出现过度调用系统资源的问题,最终导致程序崩溃。
最终我们选取C++中的unsigned__int64类型变量进行计算(相当于longlong类型),它能够满足0<a<b<1000范围内的埃及分数求解问题】