ExcelTip.Net留存知识帖 ---【注:附件之前被网盘供应商清空后,现已修复-现已修复-现已修复为本地下载!】
现在位置:首页 > E文精选 > Excel VBA > 关于组合数字相加之和等于56的解题思路分享

关于组合数字相加之和等于56的解题思路分享

作者:绿色风 分类: 时间:2022-08-17 浏览:487
楼主
kevinchengcw
本题的难点在于数字组合的个数不定,所以没有办法利用确定的变量来完成,在本例中运用了字典与数组相结合的方式对数字进行组合,思路说明如下:
1. 获得数据区域,并设置循环进行取数;
2. 利用字典存储相关数据,key存序号,item存数值,Dic用来存储全部数字,Dic2用于存储当前加和数字,当Dic2中的数值匹配时从Dic里移除对应的值,这样Dic最终剩余的是不能匹配的数值;
3. 记住累加的数的起始位置,向下方累加,当累加之和与56的差值介于数据区的最小值与最大值之间时,向下方未累加的数据区寻找一个刚好与现有加和值相加等于56的数字;
4. 如果未找到,自动放弃起始位置的数字,起始位置下移,再重复3的步骤;
5. 找到符合的组合后,将字典中内容输出到指定区域,并从Dic里移除对应数值;
6. 将最终无法匹配的数据(即Dic里剩余的数字)输出在最后。

代码如下:
  1. Sub test()
  2. Dim Dic, Dic2, Arr, Arr2
  3. Dim M, N, I, A, B, X, Y As Integer
  4. Dim WF
  5. On Error GoTo finish   '之所以设置这个是因为最终剩余的值组合没办法符合要求的时候没办法清空数组,所以利用二次添加出错跳出循环
  6. X = 4  '数据输出的起始列号
  7. Y = 6  '数据输出的起始行号
  8. B = 0  '行数增加的次数
  9. Set WF = WorksheetFunction
  10. Set Dic = CreateObject("scripting.dictionary")   '创建字典
  11. Set Dic2 = CreateObject("scripting.dictionary")
  12. For M = 2 To [a65536].End(3).Row   '循环将数据区数据存入字典中,以序号为Key,对应数值为Item
  13.     Dic.Add Cells(M, 1).Value, Cells(M, 2).Value
  14. Next M
  15. Do While WF.Sum(Dic.items) >= 56   '设置循环为当字典加和大于56时重复循环
  16.     Arr = Dic.keys   '将字典的keys赋值给数组,便于循环取用
  17.     M = 0  '用于存储加和的变量初始赋值
  18.     For I = LBound(Arr) To UBound(Arr)  '循环相加字典中对应的数值
  19.         M = M + Dic(Arr(I))
  20.         Dic2.Add Arr(I), Dic(Arr(I))   '并将已相加过的数据赋值给字典2(如果相加和等于56后便于删除字典中的对应项)
  21.         If 56 - M <= WF.Max(Dic.items) And 56 - M >= WF.Min(Dic.items) Then  '当加和与56的差小于或等于现有值序列的最大值且大于或等于现有值序列的最小值时进入内循环
  22.             For N = I + 1 To UBound(Arr)  '内循环从当前索引值的下一个开始到最后
  23.                 If M + Dic.Item(Arr(N)) = 56 Then  '逐个相加测试,如果所得值等于56,则
  24.                     Dic2.Add Arr(N), Dic(Arr(N))  '先将适合的值的信息加入到字典2
  25.                     Arr2 = Dic2.keys   '将字典2的keys赋值给数组2
  26.                     Cells(Y - 1, X) = "序号"    '输出数据的标题
  27.                     Cells(Y - 1, X + 1) = "数值"
  28.                     For A = LBound(Arr2) To UBound(Arr2)  '循环输出合格的数据信息
  29.                         Cells(Y, X) = Arr2(A)
  30.                         Cells(Y, X).Offset(0, 1) = Dic2(Arr2(A))
  31.                         Y = Y + 1
  32.                         Dic.Remove Arr2(A)  '删除字典中的已输出项目
  33.                     Next A
  34.                     Erase Arr2   '清空数组2
  35.                     Dic2.RemoveAll   '清空字典2
  36.                     X = X + 3  '改变输出数据的位置数据
  37.                     If X > 14 Then
  38.                         B = B + 1
  39.                         X = 4
  40.                     End If
  41.                     Y = 6 + 14 * B
  42.                     GoTo skip   '执行完上述动作后跳转到下一次循环
  43.                 End If
  44.             Next N
  45.         End If
  46.     Next I
  47. skip:
  48. Loop
  49. finish:  '当剩余数据无法符合进二次操作字典添加出错会跳转到此,则此时可完成剩余数值处理工作
  50. Cells(Y - 1, X) = "序号"   '输出数据标题
  51. Cells(Y - 1, X + 1) = "未用数"
  52. For N = LBound(Arr) To UBound(Arr)  '循环将剩余数据输出
  53.     Cells(Y, X) = Arr(N)
  54.     Cells(Y, X + 1) = Dic(Arr(N))
  55.     Y = Y + 1
  56. Next N
  57. Set Dic = Nothing   '清除项目
  58. Set Dic2 = Nothing
  59. MsgBox "组合查找完毕"  '显示提示框
  60. End Sub
具体内容详见附件。
求数值组合之和为56.rar
2楼
shibo79
好像这个VBA 不可以实用于SINGLE数值,当100个数都是由含有小数的数据组成时,函数只能执行一次,无法进入循环,楼主不防试一试
3楼
shibo79
数例重新上传,请楼主或高手看看能否实现
求数值组合之和为56修改数例.rar
4楼
kevinchengcw
对于数值差过大的数现在确实没有良好解决,因为这可能涉及到各数值之间需要间隔很多行,暂时想到的唯穷举法一途了,不知楼上有何高见
5楼
wangqilong1980
好,支持一下小7~
6楼
liuguansky
楼上的有才啊
7楼
吉七儿
8楼
wqfzqgk
测试有小数时有点缺陷
9楼
xyh9999
学习K哥的思路
10楼
wise
学习了
11楼
gouweicao78
7粉,你这让K哥情何以堪啊
12楼
poiuyman5
interesting.

免责声明

有感于原ExcelTip.Net留存知识的价值及部分知识具有的时间限定性因素, 经与ExcelTip.Net站长Apolloh商议并征得其同意, 现将原属ExcelTip.Net的知识帖采集资料于本站点进行展示, 供有需要的人士查询使用,也慰缅曾经的论坛时代。 所示各个帖子的原作者如对版权有异议, 可与本人沟通提出,或于本站点留言,我们会尽快处理。 在此,感谢ExcelTip.Net站长Apolloh的支持,感谢本站点所有人**绿色风(QQ:79664738)**的支持与奉献,特此鸣谢!
------本人网名**KevinChengCW(QQ:1210618015)**原ExcelTip.Net总版主之一

评论列表
sitemap