穷举求24的算术式--完成弋一凉同学作业
前天看到弋一凉同学的帖子“VB编程问题求解”,觉得有点意思,很有挑战性,当时就有兴趣做一下,无奈智商有限,再加上工作忙,一直都没有头绪。这两天放端午假,就抽了点时间仔细考虑了下,万事就怕认真,一认真思路就渐渐明晰,解决方法步骤也慢慢建立。我首先重复下弋一凉同学的帖子内容:输入任意四个整数(0到10),运算符只有加减乘除,还有括号.每个数只能且必须用一次。要求判断这些表达的结果中是否有24。如果有,输出计算表达式:如输入4,6,1,1 输出 4*6*1*1 =24 (允许有括号)。
我想就事论事,该题只是对4个小于10的数穷举算术式,因此我不考虑5个以上的数,也不考虑大于10的数,这样一来程序设计就单纯多了。下面我就谈谈程序设计思路。
根据题意,首先必须用到数字的排列组合算法,为什么要用到排列组合呢?这就要我们先理解算术式;我们首先可以认为这种算术式是一串有规律的字符串,字符串的格式是ApBpCpD,其中ABCD代表参与运算的数字,他们是用运算符p间隔开的,当p全部是“+”号时,根据加法交换率,数字在任何位置结果都一样,但当p为其他运算符时,数字在不同位置结果就不一样了,因此,我们需要数字在不同位置的排列组合,以得到不同的运算结果。一组数字排列组合的总的个数为1*2*3*…*n,因此四个数的排列组合总数即为1*2*3*4=24种,用程序实现排列组合的方法有很多种,风吹过b提出的循环方法就是一个,即4个数用4个循环,5个数用5个循环,但如果数据个数不确定的话,你怎么知道用几个循环?因此这种方法不具备通用性,列举所有排列组合的通用方法是使用函数递归方法,它类似于冒泡法排序,让每个数都在每个位置和其他数组合一次。所谓函数递归就是让函数自己调用自己,是程序设计里最头痛的一种算法,它很容易让程序陷入死循环,让程序员走火入魔,因为你的大脑也死循环了。网上可以找到很多排列组合的算法,热衷于设计彩票预测程序的朋友一定熟悉这种算法,朋友们可以找找看。
参与计算的4个数排列组合算法解决后,就是对运算符的穷举,首先我们要看看有几类运算符;“+-*/”肯定是必不可少的,接下来看看包含括号运算的类型有几种?因为是四个数的运算,括号可以包含3个数,也可以包含2个数,再就是括号只有在“*/”前后运算才有效,而加减只需要顺序运算,括号运算和不需括号运算的结果一样;这样一来,我总结出了10种类型的括号运算,分别用字母“a”到“j”表示,同时我定义了两个字符串常数,作为运算符穷举的依据,这两个常数如下:
Const Oper = "+,-,*,/,a,b,c,d,e,f,g,h,i,j" '运算符
Const OperB = "*2,*3,/2,/3,2*,3*,2/,3/,2*2,2/2"
'含括号的运算符种类,顺序对应运算符的a,b,c,d,e,f,g,h,i,j
在运算符种类中,“*2”意思是*号后面括号括2个数,如式子“2*(3+5)+6”,它对应的初始算术式是“2a3+5+6”,我专门写了个函数getExpre解释这种对应关系,最终还原为标准运算符,再举个例子,假如初始算术式为“3+5i6-2”,i对应的运算符种类是2*2,它表示*前面括2个数,后面也括两个数,所以最终算术式即(3+5)*(6-2),还举个括号套括号的例子,比如算术式(2*(5+3))*2,这种算术式的初始式子应该是怎样的呢?根据前面的理解,该算术式的初始式子应该是2a5+3f2,因为a对应的括号运算符种类为*2,意思是乘法,后面括两个数,而f对应的种类为3*,意思也为乘法,前面括3个数运算;至此,我已经对括号运算符的种类定义明白,这十种类型只针对4个数运算的,如果参与运算的种类越多,括号运算符的种类也越多,到时,可能应该总结个更好的表达方法和算法。
当运算符的种类确定后,就可以利用穷举法,遍历对应位置的运算符,因为4个数的算术式只需要3个运算符连接,而每个运算符的种类有14个,因此只需要设计一个3位数的14进制计数器即可穷举所有的运算符组合,从而穷举出一组数据的某个排列的所有算术式,一组数据某个排列的所有算术式的数量为14*14*14=2744种,当然其中包含不合格的算式(主要针对括号,getExpre函数可以过滤掉),而所有排列的算式数量为24*14*14*14=65856个,因此,如果你电脑运算速度不快的话,是要等上一段时间才能获得结果的。
当获得正确的算术表达式后,你怎样运算获得结果呢?要知道getExpre函数返回的是也表达式字符串,而vb是不具备字符串做四则混合运算功能的,不会需要我再编个四则运算的函数吧!幸好,VB为我们提供了很多类,有一种类就具备字符串算术式的四则混合运算功能,这个类就是ScriptControl类,使用这个类之前你需要引用一个COM控件,该控件就是Microsoft Script Control 1.0,对应的文件名称为msscript.ocx,在system32目录下都有这个文件,如果没有,请下载一个,并用regsvr32 –s msscript.ocx命令注册即可,在VB里引用该COM控件的方法是,点击菜单“工程---引用”,即会弹出一个引用窗口,找到Microsoft Script Control 1.0并勾选上即可,应用的方法如下:
首先在VB中新建一个EXE应用工程,引用Microsoft Script Control 1.0,在窗口中放一个command命令按钮控件,双击该控件即可添加其click事件代码如下(见下面),然后运行工程,按按钮,如果有24的消息提示窗口则说明成功。
Private Sub Command1_Click()
Dim b as New ScriptControl, i as Integer
b.Language = "VBScript"
i = b.Eval(“(2*(5+1))*2”)
MsgBox i
End Sub
好了,关于求24算式的主要思路已阐述完毕,一家之言,仅供参考。相信还有比我思路更简洁更科学的,我这也就起个抛砖引玉的作用吧。我这次就只提供完成后的程序,不再提供源代码了,这主要是促进坛友们多点自力更生的精神,少点拿来主义的思想,在程序里我有联系方式,有需要源代码的请按那个提示联系我,并一定注明“VB6论坛 用户名”否则我不提供源代码。祝各位编程愉快!
2011-06-06 Lowxiong
求24算式.rar
(9.76 KB)
2011-6-7 6:00更新了
[ 本帖最后由 lowxiong 于 2011-6-8 14:36 编辑 ]