| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1919 人关注过本帖
标题:穷举求24的算术式--完成弋一凉同学作业
只看楼主 加入收藏
lowxiong
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:27
帖 子:653
专家分:3402
注 册:2008-5-7
结帖率:100%
收藏
已结贴  问题点数:20 回复次数:8 
穷举求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 编辑 ]
搜索更多相关主题的帖子: 解决方法 表达式 
2011-06-06 14:48
wube
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:23
帖 子:1820
专家分:3681
注 册:2011-3-24
收藏
得分:10 
穷举求24的算术式...
http://www.

不要選我當版主
2011-06-08 12:35
wube
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:23
帖 子:1820
专家分:3681
注 册:2011-3-24
收藏
得分:0 
求24点,学递归
    作者:邓蔚
    求算24点是一个极为有趣的大众智力游戏,深得许多人的喜欢。但你有没有遇到过求不出解的情况呢?是自己没有想出来还是确实无解?很难判断吧!有没有想过用电脑来求解呢。如果你有一点点VB的基础,那就让我们一起来看看该怎样用VB来求算24点吧。
    电脑的思维可与人脑大相迳庭。任意四个数,中间该填加号还是减号或是乘号、除号,我们一般是靠经验迅速判断的。一般来说人脑是不可能把非常复杂的所有可能的情况一一列出来检验的(我们称这种方法叫遍历),而电脑却凭借其计算速度,往往用那种所谓的死办法出奇制胜。并且根据计算机的特点,人们研究出了很多种算法来解决实际中的问题。例如我们这里要用到的递归就是其中的一种。
    一、解决思路
    不知你听过汉诺塔的游戏吗?那便是递归的一个经典例子。所谓递归,用通俗的语言来讲就是反覆做一件类似的事情,将一件复杂的事情化为若干简单的事情而重复做。用程序的语言表示就是一个函数(也可以是多个函数)反覆调用自己。其实质目标还是由多化少、由繁至简。求两个数加减乘除的结果为24的解法是显而易见的,无论是谁或电脑都可以轻而易举地解决。那我们要求4个数加减乘除的结果为24,可不可以由繁至简化为只要求两个数加减乘除的结果为24呢?答案当然是肯定的。我们先将求4个数加减乘除的结果为24的问题化为求其中任意两个数的加减乘除的结果与剩余两个数(总共3个数)加减乘除的结果为24的问题。再用类似的方法将求3个数加减乘除的结果为24的问题,化为求2个数的问题。是不是很明白?
    举个例子吧:例如1、2、3、4这四个数。先取1和2出来,我们的问题是不是化为了分别求3(=1+2)、3、4;2(=1?2)、3、4;-1(=1-2)、3、4;1(=2-1)、3、4;2(=2/1)、3、4;0.5(=1/2)、3、4这6组数的加减乘除的结果为24的问题。然后考虑3个数的问题,如第一组3、3、4,再任取两个数如前面两个3,最终化为6(=3+3),4;0(=3-3),4;9(=3?3),4;1(=3/3),4这4组两个数的问题。结果很快出来了:6?4=24,而6=3?3,其中的一个3=1+2。当然一般的结果是要遍历所有的可能才得出的。
    思路出来了,我们便开始将它化为程序代码。首先是构造递归主模块Function Iis24?ByRef a??? ByRef i? As Boolean,其中数组a??中存放我们要求解的数,i是a??中数的个数。我们要求解1、2、3、4,便调用Iis24?a??? 4?,其中的a?1?=1?a?2?=2?a?3?=3?a?4?=4。化为3个数时,取a??中的两个数进行加减乘除,将结果放入c?1?,a??中剩余的两个数放入c?2?、c?3?,再调用Iis24 ?c??? 3?,依此再类推。Iis24返回的是布尔值,True表示有解,反之无解。然后它还应当包含i=2时的求解。然后还应该有一个计算的模块Function Sum?n1? n2? f?,n1、n2表示用于计算的2个数,f表示计算符号(1表示加、2表示减……),该模块用于把数字和计算符号转化为相应的结果,因为要用循环遍历加减乘除,用数字表示计算符号更方便一些。然后还有输出模块,将内部的表示(符号1、2、3、4)在转化为外部的表示(+、-、?、\)。这样,大概的程序就出来了。最后是界面的制作,考虑输入和输出。我的程序界面如图:4个TextBox是一个控件数组,取名为txtNum ??;一个按钮名为cmdCount24;输出的是一个ListBox名为List1。
    不知你通过这个程序对递归有一个更深入的了解吗?理解了思路再好好地分析实现的代码,应该会有所收获的。
    二、实现代码
    具体的代码如下:
    Function Sum?n1? n2? f?
    On Error Resume Next   '用错误陷阱排除除数可能为0的错误
    '计算模块
    Sum = n1
    If f = 1 Then
    Sum = Sum + n2
    ElseIf f = 2 Then
    Sum = Sum - n2
    ElseIf f = 3 Then
    Sum = Sum ? n2
    ElseIf f = 4 Then
    Sum = Sum / n2
    End If
    End Function
    Function ShowSum?n1? n2? f?
    '输出模块
    ShowSum = CStr?n1?
    If f = 1 Then
    ShowSum = ShowSum + "+" + CStr?n2?
    ElseIf f = 2 Then
    ShowSum = ShowSum + "-" + CStr?n2?
    ElseIf f = 3 Then
    ShowSum = ShowSum + "?" + CStr?n2?
    ElseIf f = 4 Then
    ShowSum = ShowSum + "/" + CStr?n2?
    End If
    End Function
    Private Sub cmdCount24_Click??
    List1.Clear
    Dim a?4?? f?4?
    For i = 0 To 3
    a?i + 1? = Val?txtNum ?i?.Text?
    Next i
    If Iis24?a??? 4? Then
    '有解
    End If
    End Sub
    Private Sub Form_Load??
    '初始化界面
    For i = 0 To 3
    txtNum ?i?.Text = Val?i + 1?
    Next i
    End Sub
    Function Iis24?ByRef a??? ByRef i? As Boolean
    '主模块
    If i = 2 Then
    '如果只剩两个数了,直接判断
    n1 = a?1?? n2 = a?2?     '读入这两个数
    For ff = 1 To 4          '遍历加减乘除(1表示加、2表示减……)
    If Sum?n1? n2? ff? = 24 Then
    '得出结果输出
    List1.AddItem "-----------"
    List1.AddItem ShowSum?n1? n2? ff? + "=" + CStr?Sum?n1? n2? ff??
    Iis24 = True
    Exit Function
    ElseIf Sum?n2? n1? ff? = 24 Then
    '得出结果输出
    List1.AddItem "-----------"
    List1.AddItem ShowSum?n2? n1? ff? + "=" + CStr?Sum?n2? n1? ff??
    Iis24 = True
    Exit Function
    End If
    Next ff
    Else
    '如果有i个数,先取两个数出来进行加减乘除
    Dim b?4?? c?4?
    For ii = 1 To i
    '取第一个数
    n1 = a?ii?
    For jj = 1 To i
    If jj <> ii Then
    '取第二个数
    n2 = a?jj?
    '剩余的数放入数组c
    nb = 2
    For kk = 1 To i
    If kk <> ii And kk <> jj Then c?nb? = a?kk?? nb = nb + 1
    Next kk
    For ff = 1 To 4  '遍历加减乘除(1表示加……)
    c?1? = Sum?n1? n2? ff?   '取出的两个数的结果放到c中
    If Iis24?c??? i - 1? Then   '递归
    List1.AddItem ShowSum?n1? n2? ff? + "=" + CStr?Sum?n1? n2? ff??
    Iis24 = True
    Exit Function
    End If
    Next ff
    End If
    Next jj
    Next ii
    End If
    End Function

不要選我當版主
2011-06-08 12:36
lowxiong
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:27
帖 子:653
专家分:3402
注 册:2008-5-7
收藏
得分:0 
嗯,看来很多人做了先行者啊。不过涉及到括号运算的还没有,再就是我的程序已经改成20以内的数运算了。感谢wube找到的许多资料,仔细看了下,我们设计的主体思路都差不多,希望对学习的人有帮助。我还是那句话,希望坛友们多点自力更生的精神,少点拿来主义的思想!只有这样才能真正成为随心所欲的程序设计者。

[ 本帖最后由 lowxiong 于 2011-6-8 13:12 编辑 ]
2011-06-08 13:09
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4947
专家分:30084
注 册:2008-10-15
收藏
得分:10 
还是回一句吧。
楼主一定要 订正 错别字 。

--------------------------
递归,一般能最快得出一组结果。
穷举法循环,能得出 所有的组的结果。
穷举法更容易理解一些。
--------------------------
我最近都没有编程环境可以用于编程。

授人于鱼,不如授人于渔
早已停用QQ了
2011-06-08 13:29
lowxiong
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:27
帖 子:653
专家分:3402
注 册:2008-5-7
收藏
得分:0 
回复 3楼 wube
你这是哪来的代码啊?根本没办法运行,复制过去尽是红的,调半天,没红的了,运行又提示下标越界,没有结果。
2011-06-08 14:00
lowxiong
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:27
帖 子:653
专家分:3402
注 册:2008-5-7
收藏
得分:0 
回复 5楼 风吹过b
,只是幽一下默,千万别介意!已改过。

[ 本帖最后由 lowxiong 于 2011-6-8 14:37 编辑 ]
2011-06-08 14:01
wube
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:23
帖 子:1820
专家分:3681
注 册:2011-3-24
收藏
得分:0 
回复 6楼 lowxiong
http://www.

有问题去找原作者吧~我只是提供方向~网路找都有的东西~

那篇是这抓的~文字档想说直接贴上来就好~反正上面有作者名字~不过好像又是你....

直接贴文档下载的网址给你~劝戒作者的重责大任就交给你了~
http://www.

一般来说这种不排版的代码不可能是我写的~看了就恶心~
类似这里版有个问贪吃蛇的~代码也是不排版~帮他排完还要帮他写注解~
算了~

刚来的时候不知道在哪看到~看贴文的排版就可以知道这帖子值不值得回之类的~
所以我才会特别注意这点~

[ 本帖最后由 wube 于 2011-6-8 19:07 编辑 ]

不要選我當版主
2011-06-08 18:47
lowxiong
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:27
帖 子:653
专家分:3402
注 册:2008-5-7
收藏
得分:0 
回复 8楼 wube
我写代码特别注重规范和写注解的,免得周期过长,总要重新读一下前面写的代码时读不懂,造成效率低下。大型的开发我还要专门写开发文档,写功能改进、修改和维护记录文档的。
2011-06-08 19:17
快速回复:穷举求24的算术式--完成弋一凉同学作业
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.043042 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved