|
本帖最后由 lichuanboy44 于 2016-5-6 11:47 编辑
最近本人在参与vbyou127 的添加数字运算的帖子中得到启发,联想到添加+-*/的数学运算,又联想到24点。
但现有网上开源的24点VBA编程,主要有递归法和Function等复杂调用,语句大多在100句左右,且过程调用较多,思路较复杂,一般人很难搞懂代码。
本程序代码较短(60句),可读性强,运用的均是基本的编程方法,且运行速度较快。
在此第一次讨论发贴,望各位高手指点,你的指点就是我的进步和收获。- Sub 逗24()
- '算法思路:如果给定的点数为a、b、c、d,运算符号为设为X、Y、Z,表达式则为:aXbYcZd
- '如果通过括号来强制规定运算的优先顺序,则共有如下5种运算模式(3!=6种,其中一种重复)
- 'ss1 = "((aXb)Yc)Zd":ss2 = "(aXb)Y(cZd)":ss3 = "(aX(bYc))Zd"
- 'ss4 = "aX((bYc)Zd)":ss5 = "aX(bY(cZd))"
- On Error Resume Next
- Application.ScreenUpdating = False
- Dim sc As Object, dd As Object, pr(1 To 5), ar
- Dim sjg! '特注:如果sjg不定义为此单精度型,则3 3 8 8为无解
- Set sc = CreateObject("ScriptControl") '核心控件,比Evaluate速度快一倍
- Set dd = CreateObject("scripting.dictionary")
- sc.Language = "vbs" '没懂不用管,反正和上面的ScriptControl配套
- tb = Timer: p = 1
- sr = Array("+", "-", "*", "/") '运算符存入数组
- arr = [C1:F1] '从指定单元格读取数据
- sjg = 24 '指定运算结果(可灵活任意指定)
- ReDim ar(1 To 4, 1 To p) '存放所有排列
- '*****************************第一步:计算出指定的四个数据的所有排列
- '本可和第二步的for循环嵌套,但那样for层数太多,不美观,且速度影响不大
- For h = 1 To 4
- For i = 1 To 4
- If i <> h Then
- For j = 1 To 4
- If j <> i And j <> h Then
- For k = 1 To 4
- If k <> j And k <> i And k <> h Then
- ReDim Preserve ar(1 To 4, 1 To p)
- ar(1, p) = arr(1, h): ar(2, p) = arr(1, i)
- ar(3, p) = arr(1, j): ar(4, p) = arr(1, k)
- p = p + 1
- End If
- Next
- End If
- Next
- End If
- Next
- Next
- '*****************************第二步:逐个取出组合数,用五大运算模式全面计算比对
- For g = 1 To UBound(ar, 2) '逐个取出组合数
- a = ar(1, g): b = ar(2, g): c = ar(3, g): d = ar(4, g)
- With sc '亦可用易懂的Evaluate替换,但分母为0时运算出错,要注意排错。
- .ExecuteStatement "a=" & a: .ExecuteStatement "b=" & b '不懂暂不管
- .ExecuteStatement "c=" & c: .ExecuteStatement "d=" & d
- For h = 0 To 3 '3个for依次取出XYZ3个+-*/运算符填入下面的运算模式
- For i = 0 To 3
- For j = 0 To 3
- X = sr(h): Y = sr(i): Z = sr(j)
- pr(1) = "((" & a & X & b & ")" & Y & c & ")" & Z & d '模式
- pr(2) = "(" & a & X & b & ")" & Y & "(" & c & Z & d & ")"
- pr(3) = "(" & a & X & "(" & b & Y & c & "))" & Z & d
- pr(4) = a & X & "((" & b & Y & c & ")" & Z & d & ")"
- pr(5) = a & X & "(" & b & Y & "(" & c & Z & d & "))"
- For k = 1 To 5
- ss = pr(k): jg = .eval(ss) = sjg '字符串求值并比对
- If jg And Not dd.exists(ss) Then dd(ss) = "" '字典存入
- Next
- Next
- Next
- Next
- End With
- Next
- '************************************
- [A1:A8000].Clear
- [A1].Resize(dd.Count, 1) = WorksheetFunction.Transpose(dd.keys)
- If [A1] = "" Then [A1] = "无解"
- [C5] = Format(Timer - tb, "0.000")
- Application.ScreenUpdating = True
- 'MsgBox Format(Timer - tb, "0.000秒")
- End Sub
复制代码
可以考虑把所有算式去重后再进行判断。这样遇到相同数的情况速度会提高。 - Sub 逗24aa()
- '算法思路:如果给定的点数为a、b、c、d,运算符号为设为X、Y、Z,表达式则为:aXbYcZd
- '如果通过括号来强制规定运算的优先顺序,则共有如下5种运算模式(3!=6种,其中一种重复)
- 'ss1 = "((aXb)Yc)Zd":ss2 = "(aXb)Y(cZd)":ss3 = "(aX(bYc))Zd"
- 'ss4 = "aX((bYc)Zd)":ss5 = "aX(bY(cZd))"
- Application.ScreenUpdating = False
- Dim ar(1 To 4, 1 To 100)
- Dim sjg! '特注:如果sjg不定义为此单精度型,则3 3 8 8为无解
- Set dd = CreateObject("scripting.dictionary")
- Set d1 = CreateObject("scripting.dictionary")
- tb = Timer
- sr = Array("+", "-", "*", "/") '运算符存入数组
- arr = [C1:F1] '从指定单元格读取数据
- sjg = 24 '指定运算结果(可灵活任意指定)
-
- '*****************************第一步:计算出指定的四个数据的所有排列
- '本可和第二步的for循环嵌套,但那样for层数太多,不美观,且速度影响不大
- For h = 1 To 4: For i = 1 To 4: For j = 1 To 4: For k = 1 To 4
- If (h - i) * (h - j) * (h - k) * (i - j) * (i - k) * (j - k) <> 0 Then
- p = p + 1
- ar(1, p) = arr(1, h): ar(2, p) = arr(1, i)
- ar(3, p) = arr(1, j): ar(4, p) = arr(1, k)
- End If
- Next: Next: Next: Next
-
- '*****************************第二步:逐个取出组合数,用五大运算模式全面计算比对
- 'On Error Resume Next
- For g = 1 To p '逐个取出组合数
- a = ar(1, g): b = ar(2, g): c = ar(3, g): d = ar(4, g)
- For h = 0 To 3: For i = 0 To 3: For j = 0 To 3 '3个for依次取出XYZ3个+-*/运算符填入下面的运算模式
- X = sr(h): Y = sr(i): Z = sr(j)
- dd("((" & a & X & b & ")" & Y & c & ")" & Z & d) = "" '运算模式,'字典存入不重复值
- dd("(" & a & X & b & ")" & Y & "(" & c & Z & d & ")") = ""
- dd("(" & a & X & "(" & b & Y & c & "))" & Z & d) = ""
- dd(a & X & "((" & b & Y & c & ")" & Z & d & ")") = ""
- dd(a & X & "(" & b & Y & "(" & c & Z & d & "))") = ""
- Next: Next: Next
- Next
- For Each pp In dd.keys
- ss = Application.Evaluate(pp)
- If CStr(ss) <> "Error 2007" Then
- If ss = sjg Then d1(pp) = ""
- End If
- Next
- '************************************
- [A1:A8000].Clear
- If d1.Count >= 1 Then [A1].Resize(d1.Count, 1) = WorksheetFunction.Transpose(d1.keys) Else [A1] = "无解"
- [C5] = Format(Timer - tb, "0.000")
- Application.ScreenUpdating = True
- End Sub
复制代码
|
评分
-
查看全部评分
|