ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 323|回复: 12

[求助] E列任意n个数相加等于28-VBA代码

[复制链接]

TA的精华主题

TA的得分主题

发表于 2024-6-16 19:03 | 显示全部楼层 |阅读模式
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 zeng3915 于 2024-6-16 19:10 编辑

各位大佬好,

请问怎么样用VBA代码算出E列任意2个,3个,4个,5个,6个,7个,8个,9个数相加=28。
举例1,2个数相加=28,结果是(目前人工检查发现没有2个数相加等于28的,但是实际上后期数据更改了,有可能会有的)
举例2,3个数相加=28,结果是E2+E3+E4,所以把对应的A列的型号放在H列,应该有很多种,把所有3个数相加的结果找出来后,隔1行放在H列
其他4个,5个,6个,7个,8个,9个的以此类推,我手动举了1个或多个例子放在G列至N列了。
我上传了图片和附件,可以下载看看,尽量算出更多的结果,因为后续我们需要根据型号算出最优解,结果多了,可能会得到最好的结果。
麻烦各位VBA大佬给点建议或者帮忙看看怎么结题吧,谢谢大佬啦!
E列任意n个数相加等于28.JPG

E列任意n个数相加等于28.zip

9.57 KB, 下载次数: 8

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-6-16 19:44 | 显示全部楼层
有没有大佬愿意帮忙看看的,拜托拜托

TA的精华主题

TA的得分主题

发表于 2024-6-16 20:11 | 显示全部楼层
Option Explicit
Sub test()

    Dim vResult(), ar, br, cr, vTemp, r&, i&, j&, m&, n&, iCol&, bytDigit As Byte, dic As Object, vKey, t#
   
   
    Application.ScreenUpdating = False
    t = Timer
    bytDigit = 0
   
    iCol = 5
    r = Cells(Rows.Count, "A").End(xlUp).Row
    vTemp = Range("A2:E" & r).Value
    ar = Application.Index(vTemp, , iCol)
   
    ReDim Preserve ar(1 To UBound(ar), 1 To 2)
    For i = 1 To UBound(ar): ar(i, 2) = i: Next i
    bSort ar, 1, UBound(ar), 1, 2
   
    n = UBound(ar)
    ReDim br(1 To n)
    r = 0
    MakeNumCount vResult, ar, br, r, 28, bytDigit
   
    Set dic = CreateObject("Scripting.Dictionary")
    n = 0
    Columns("G:XFD").Clear
    If r Then
        ReDim ar(1 To UBound(vResult, 2), 1 To 2)
        For i = 1 To UBound(vResult, 2)
            ar(i, 1) = vResult(1, i)
            ar(i, 2) = vResult(2, i)
        Next i
        
        ShellSort2D ar, 1, UBound(ar), 1, 2, 1
        For i = 1 To UBound(ar)
            dic(ar(i, 1)) = dic(ar(i, 1)) & "|" & ar(i, 2)
        Next i
        
        For Each vKey In dic.keys
            n = n + 1
            br = Split(dic(vKey), "|")
            m = 1
            
            ReDim ar(1 To UBound(br) * (vKey + 1), 0)
            ar(m, 0) = vKey & "个相加结果等于28"
            For i = 1 To UBound(br)
                cr = Split(br(i), ",")
                For j = 0 To UBound(cr)
                    m = m + 1
                    ar(m, 0) = vTemp(cr(j), 1)
                Next j
                If i < UBound(br) Then m = m + 1
            Next i
            Cells(1, n + 6).Resize(m) = ar
            Columns(n + 6).AutoFit
        Next
    End If
   
    Application.ScreenUpdating = True
    MsgBox "执行完毕!_用时:  " & Format(Timer - t, "0.00") & "  秒,共发现 " & r & " 组", 64
End Sub


Function MakeNumCount(ByRef vResult(), ByVal ar, ByVal br, ByRef iGroup&, ByVal iSum&, ByVal bytDigit As Byte, Optional ByVal iCount& = 0, _
    Optional ByVal iEleNum& = 0, Optional ByVal iTemp& = 0, Optional ByVal iStart& = 1, Optional ByVal iChkNum& = -1)
    Dim i&, j&, iNum&, cr(), strJoin$, r&, m&
     
    iChkNum = iChkNum + 1
    If iEleNum * (iEleNum = iChkNum) Then Exit Function
   
    For i = iStart To UBound(br)
        If iCount * (iGroup = iCount) Then Exit Function
        
        iNum = ar(i, 1) * 10 ^ bytDigit: br(i) = iNum
        If iTemp + iNum > iSum Then Exit Function
            
        If iTemp + iNum = iSum Then
            r = 0:  strJoin = ""
            For j = 1 To UBound(br)
                If br(j) <> "" Then
                    strJoin = strJoin & IIf(br(j) < 0, "", "+") & br(j) * 10 ^ -bytDigit
                    r = r + 1
                    ReDim Preserve cr(1 To r)
                    cr(r) = ar(j, 2)
                 End If
            Next j
            
            m = IIf(iEleNum = 0, r, iEleNum)
            If r = m Then
                iGroup = iGroup + 1
                ReDim Preserve vResult(1 To 2, 1 To iGroup)
                vResult(1, iGroup) = r
                vResult(2, iGroup) = Join(cr, ",")
            End If
        ElseIf iTemp + iNum < iSum Then
            Call MakeNumCount(vResult, ar, br, iGroup, iSum, bytDigit, iCount, iEleNum, iTemp + iNum, i + 1, iChkNum)
        End If
        br(i) = ""
     Next i
End Function

Function bSort(ar, iFirst&, iLast&, iLeft&, iRight&, _
    Optional iKey& = 1, Optional isOrder As Boolean = True)
    Dim i&, j&, k&, vTemp
   
    For i = iFirst To iLast - 1
        For j = iFirst To iLast + iFirst - 1 - i
            If ar(j, iKey) <> ar(j + 1, iKey) Then
                If ar(j, iKey) < ar(j + 1, iKey) Xor isOrder Then
                    For k = iLeft To iRight
                        vTemp = ar(j, k)
                        ar(j, k) = ar(j + 1, k)
                        ar(j + 1, k) = vTemp
                    Next
                End If
            End If
        Next j
    Next i
End Function
Function ShellSort2D(ByRef ar, ByVal iFirst&, ByVal iLast&, ByVal iLeft&, _
    ByVal iRight&, ByVal iKey&, Optional isOrder As Boolean = True)

    Dim iRowSize&, vTemp, interval&, i&, j&, k&

    ReDim vTemp(iLeft To iRight)
    iRowSize = iLast - iFirst + 1
    interval = 1

    If iRowSize > 13 Then
        Do While interval < iRowSize
            interval = interval * 3 + 1
        Loop
        interval = interval \ 9
    End If
   
    Do While interval
        For i = iFirst + interval To iLast
            For j = iLeft To iRight
                vTemp(j) = ar(i, j)
            Next
            If isOrder Then
                For k = i - interval To iFirst Step -interval
                    If ar(k, iKey) <= vTemp(iKey) Then Exit For
                    For j = iLeft To iRight
                         ar(k + interval, j) = ar(k, j)
                    Next j
                Next k
            Else
                For k = i - interval To iFirst Step -interval
                    If ar(k, iKey) > vTemp(iKey) Then Exit For
                    For j = iLeft To iRight
                        ar(k + interval, j) = ar(k, j)
                    Next j
                Next k
            End If
            For j = iLeft To iRight
                ar(k + interval, j) = vTemp(j)
            Next
        Next i
        interval = interval \ 3
    Loop

End Function

TA的精华主题

TA的得分主题

发表于 2024-6-16 20:12 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
组合的数据很多,确认要那么多。。。

E列任意n个数相加等于28.rar

25.08 KB, 下载次数: 12

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2024-6-16 20:16 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
8个分别写,会写一个就会写8个了。写一个9个数的,基本删删就得到其他7个数的了

TA的精华主题

TA的得分主题

发表于 2024-6-17 00:05 | 显示全部楼层
香川递归版 E列任意n个数相加等于28.zip (20.61 KB, 下载次数: 11)
Dim a(), b(), h&, m&, n&
Sub test2() 'liulang0808 字典凑数 不用字典改成数组版 by kagawa 2018/08/14
    Dim i&, t&
   
    ActiveSheet.UsedRange.Offset(1, 6).ClearContents '清空输出区域
   
    m = [e1].End(4).Row - 1 '原始数据个数m
    a = WorksheetFunction.Transpose([e2].Resize(m)) '读取A2开始的原始数据
    ReDim b(m) '代替字典 记录凑数组合的数组b
   
    h = 28 '凑数目标和h
    n = 1 '输出起始行位置
   
    Call dg2(0, 0) '递归组合进行凑数
   
    MsgBox n '凑数组合结果总数n
End Sub
Sub dg2(r&, j&) '递归组合
    Dim i&, t&
    For i = j + 1 To m '遍历原始数据中剩余元素
        t = a(i): b(i) = t '数组b记录当前i位置加入组合的数t
        If r + t = h Then '累计相加正好相等时 为一组解
            n = n + 1 ': Cells(n, 3).Resize(, m) = b '输出解
            x = Application.Count(b)
            lr = Cells(Rows.Count, x + 5).End(3).Row
            If lr = 1 Then lr = 2 Else lr = lr + 2
            For y = 0 To m
                If Len(b(y)) > 0 Then
                    Cells(lr, x + 5) = Cells(y + 1, 1)
                    lr = lr + 1
                End If
            Next
        ElseIf r + t < h Then '不足时
            Call dg2(r + t, i) '继续递归凑数
        End If
        b(i) = "" '递归回溯时数组记录中清除当前i位置的数t
    Next
End Sub


TA的精华主题

TA的得分主题

发表于 2024-6-17 16:14 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
参与下,执行效果
录制_2024_06_17_16_14_03_780.gif

TA的精华主题

TA的得分主题

发表于 2024-6-17 16:15 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2024-6-17 16:15 | 显示全部楼层
JS代码
  1. function 生成排列组合(){
  2.         let obj=Range("a1").CurrentRegion.Value2.slice(1).reduce((obj,[a,,,,b])=>(obj[a]=b,obj),{})
  3.         for (let i=2;i<=9;i++){
  4.                 let arr=[[`${i}个相加结果等于28`]].concat(myplzh1(Object.keys(obj),"组合",i,obj));
  5.                 Cells.Item(1,i+5).Resize(arr.length,1).Value2=arr;
  6.         }
  7. }

  8. function myplzh1(szarr,type,n,obj){
  9.         let arr=[],temp=new Array(n).fill(null);
  10.         let h=0;                                        //h:统计递归所在的层数,不超过最底层(n-1)
  11.         function getplzh(k){                //k:递归循环的起始位置
  12.                 for (let i=k;i<szarr.length;i++){
  13.                         if (temp.includes(szarr[i])) continue;                //统计不重复值
  14.                         temp[h]=szarr[i];
  15.                         if (temp[n-1]!=null){
  16.                                 if (temp.reduce((a,b)=>a+obj[b],0)==28) arr.push(...(temp.map(x=>[x]).concat([[]])));
  17.                         }
  18.                         if (h<n-1){                                        //判断是否到达底层(n-1),未达到则继续往下一层递归
  19.                                 h++;                                        //层数递增
  20.                                 getplzh(type=="组合"?i+1:0);                //递归,如果是组合,起始位置从i+1开始,否则从0开始
  21.                         }
  22.                 }
  23.                 temp[h]=null;                //退出本层之前,将元素位置置空(null)
  24.                 h--;                                //循环结束,退回到递归的上一层
  25.         }
  26.         getplzh(0);
  27.         return arr;
  28. }
复制代码

TA的精华主题

TA的得分主题

发表于 2024-6-17 16:16 | 显示全部楼层
附件,WPS测试有效,我只验证了三个组合,好像没错,其他的没有验证

E列任意n个数相加等于28.zip

206.9 KB, 下载次数: 1

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-6-29 16:13 , Processed in 0.040147 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表