ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[求助] xiaomage1的求助:万千百十个组合分析

[复制链接]

TA的精华主题

TA的得分主题

发表于 2012-4-3 18:44 | 显示全部楼层 |阅读模式
本帖已被收录到知识树中,索引项:其他结构和算法
有个新手,ID:xiaomage1

在我的帖子里提了问题。
我做了解答,可是后来他又有问题了……

于是,我建议他要新开帖子讨论。

他可能用手机不方便,我就来开帖了。

……………………………………

以下是问题:
万千百十个共5个数位,其中3个数位有0-9的数值,另外2个数位是空的,这样3个数值2个空就成为1种组合。
如: 123__,1_2_3,__123这样的。(其中_下划线表示该数位没有数值。)

现在xiaomage1有很多这样的不同数位3个数的组合,
这些组合中有些正好能符合凑成一个完整5位数,即:
123__
_235_
__356
这样几个组合,就可以凑成一个12356的五位数。

即,这个五位数的任取3个数位的组合结果,都在原始数据中存在。



他想知道,符合条件的五位数一共有多少。

附件是xiaomage1第一次提问时的附件。

范例及问题.rar

24.9 KB, 下载次数: 48

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-4-3 18:49 | 显示全部楼层
经过原理分析,我做了解答。

编写的代码,虽然不算太复杂,但是也很繁琐。
见链接16楼
http://club.excelhome.net/thread-742341-2-1.html


废了不少力气,把小马哥1的【万千百十个】五位数字组合分析程序编写完成了。

考虑到程序接口方便,我把数据形式又改了。
现在是改成,各种数字直接按ABCDE,即【万千百十个】方式拆开填入相应列。

这样计算就很方便了。

万千百个十组合分析.rar

37.64 KB, 下载次数: 65

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-4-3 18:51 | 显示全部楼层
这个组合分析的要点,是对各种类型的组合不要产生遗漏。

主要思路如下:
每一组数值,如ABC,首先要检查它们和其它数字组合中,
要求其中有2个是相同的,然后才能符合条件,让新元素加入。

那么,假设对于ABC,则它任取2个以后的组合形式一共有3种:
1. A - BC
2. B - AC
3. C - AB

接着,依次检查所有数据中,符合有2个值相同的组合,即:
1. A - BC  →  检查 BC-D 或 BC-E
2. B - AC  →  检查 AC-D 或 AC-E
3. C - AB  →  检查 AB-D 或 AB-E

然后,对于这新的6种组合,都要再次进行检查:
举例,如对于A-BC-D 组合,且符合BC相同时,可以确定D值有效,
接下来,对于BCD这3个值的任意取2数进行组合检查,则有:
1. B -CD  →  CD-E  (即找到有CD也符合相同时,可最终确定 E值)
2. C -BD  →  BD-E  (即找到有BD也符合相同时,可最终确定 E值)
3. D -BC  →  BC-E  (即找到有BC也符合相同时,可最终确定 E值)

………………

这样,把第一步得到的前面6种组合,即:
1. A - BC  →  检查 BC-D 或 BC-E
2. B - AC  →  检查 AC-D 或 AC-E
3. C - AB  →  检查 AB-D 或 AB-E

其中每一个组合再产生3种可能的组合进行检查,就能得到所有的符合条件的组合结果了。

…………

总之,对于m个原始3位数的值,
都要检查 6*3*m=18*m 种组合。




为了高效计算,我在sheet2中做了辅助参数表,并使用了字典定位方式。
当数据量不大时,计算速度倒还比较快。


TA的精华主题

TA的得分主题

 楼主| 发表于 2012-4-3 18:53 | 显示全部楼层
后来,楼主又提出了进一步的要求,得到的五位数,必须符合任意位置的10种组合都要有,缺一不可。


于是,我把提取到的结果,再次和原始数据比对,最后就得到了正确的结果。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-4-3 18:57 | 显示全部楼层
但是,当楼主再次提供7842行数据要求分析时,
发现原来的程序,因为需要反复循环计算,耗时太多了,每一行数据的完全循环比对,就要将近1分钟。

那7842行数据,将耗时17个小时。


这样的程序,是失败了。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-4-3 19:03 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
于是我想了又想,发现一个捷径:

我根本不需要对原始数据进行组合来产生有效的五位数,
那样做计算量太大。

我仅仅需要,模拟生成所有的五位数,(即0-99999)
然后和原始数据比对,检查是否这个五位数的10种位数组合都存在于原始数据中,就行了。


…………
想到这些以后,我马上去写代码,代码写完,运行……结果10多秒就能比对计算完成了……

真是,踏破铁鞋无觅处,得来全不费功夫。
【代码再多无用处,算法对路不费力】




万千百个十组合快速分析.rar

123.04 KB, 下载次数: 109

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-4-3 19:11 | 显示全部楼层
很意外地是,生成0-99999五位数,并拆分成万、千、百、十、个位五个数值时,
以下代码的写法居然相差很大。
  1. Sub SpeedCompare()
  2.     Dim i&, m%
  3.     m = 1 '此处m是设置运行次数。10的m次幂次。
  4.     '如果程序单次运行时间很短,可以设置m值=3 即运行1000次,
  5.    '甚至可设置m=6,即运行1百万次。
  6.    '如果程序单次运行时间已经较长,则设置m=0,只运行10的0次方=1次。
  7.    
  8.     tms = Timer
  9.     For i = 1 To 10 ^ m
  10.         Call get1
  11.     Next
  12.     MsgBox Format(Timer - tms, "0.0000s")
  13.    
  14.     tms = Timer
  15.     For i = 1 To 10 ^ m
  16.         Call get2
  17.     Next
  18.     MsgBox Format(Timer - tms, "0.0000s")
  19.    
  20. End Sub

  21. Sub get1() '实际采用的算法,仅仅调整进位部分
  22.     Dim i&, j%
  23.     Dim a%(4)
  24.     For i = 0 To 3
  25.         a(i) = 0
  26.     Next
  27.     a(4) = -1
  28.     For i = 0 To 99999
  29.         For j = 4 To 0 Step -1
  30.             If a(j) < 9 Then
  31.                 a(j) = a(j) + 1: Exit For
  32.             Else
  33.                 a(j) = 0
  34.             End If
  35.         Next
  36.     Next
  37. End Sub

  38. Sub get2() '传统算法思路,用right整形以后,用mid拆分
  39.     Dim i&, j%, s$
  40.     Dim a%(4)
  41.     For i = 0 To 99999
  42.         s = Right("0000" & i, 5)
  43.         For j = 0 To 4
  44.             a(j) = Mid(s, j + 1, 1)
  45.         Next
  46.     Next
  47. End Sub
复制代码

点评

嗯,看来彩票业务也能促进学习  发表于 2012-4-4 21:03

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-4-3 19:12 | 显示全部楼层
最终解决问题的代码如下:
  1. Sub test2()
  2.     tms = Timer
  3.    
  4.     Dim i&, j%, k%, l&
  5.     Sheets(1).[f2].Resize(65535, 5) = ""
  6.    
  7.     arr = Sheets(1).[a1].CurrentRegion
  8.     Set d = CreateObject("Scripting.Dictionary")
  9.     s = Array("万", "千", "百", "十", "个")
  10.     For i = 2 To UBound(arr)
  11.         arr(i, 6) = ""
  12.         arr(i, 7) = ""
  13.         arr(i, 8) = ""
  14.         For j = 1 To 5
  15.             If arr(i, j) = "" Then
  16.                 arr(i, 8) = arr(i, 8) & "_"
  17.             Else
  18.                 arr(i, 6) = arr(i, 6) & Chr(64 + j)
  19.                 arr(i, 7) = arr(i, 7) & s(j - 1)
  20.                 arr(i, 8) = arr(i, 8) & arr(i, j)
  21.             End If
  22.         Next
  23.         d(arr(i, 8)) = 1
  24.     Next
  25.     Sheets(1).[a1].CurrentRegion = arr
  26.    
  27. '    MsgBox Timer - tms
  28. '    tms = Timer
  29.    
  30.     Dim a%(4)
  31.     Dim b(65535, 0)
  32.     Dim c(9)
  33.    
  34.     For j = 0 To 4
  35.         a(j) = 0
  36.     Next
  37.     a(4) = -1
  38.     For i = 0 To 99999
  39.         For j = 4 To 0 Step -1
  40.             If a(j) < 9 Then
  41.                 a(j) = a(j) + 1: Exit For
  42.             Else
  43.                 a(j) = 0
  44.             End If
  45.         Next
  46.         c(0) = a(0) & a(1) & a(2) & "__"
  47.         c(1) = a(0) & a(1) & "_" & a(3) & "_"
  48.         c(2) = a(0) & a(1) & "__" & a(4)
  49.         c(3) = a(0) & "_" & a(2) & a(3) & "_"
  50.         c(4) = a(0) & "_" & a(2) & "_" & a(4)
  51.         c(5) = a(0) & "__" & a(3) & a(4)
  52.         c(6) = "_" & a(1) & a(2) & a(3) & "_"
  53.         c(7) = "_" & a(1) & a(2) & "_" & a(4)
  54.         c(8) = "_" & a(1) & "_" & a(3) & a(4)
  55.         c(9) = "__" & a(2) & a(3) & a(4)
  56.         
  57.         k = 0
  58.         For j = 0 To 9
  59.             k = k + d(c(j))
  60.         Next
  61.         If k = 10 Then
  62.             b(l, 0) = "'" & Right("0000" & i, 5): l = l + 1
  63.         End If
  64.     Next
  65.     Sheets(1).[j2].Resize(l) = b
  66.    
  67.     MsgBox Timer - tms
  68.    
  69. End Sub
复制代码

TA的精华主题

TA的得分主题

发表于 2012-4-3 19:20 | 显示全部楼层

RE: xiaomage1的求助:万千百十个组合分析

香川群子 发表于 2012-4-3 19:12
最终解决问题的代码如下:

群子老师,谢谢您

TA的精华主题

TA的得分主题

发表于 2012-4-3 19:51 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
高,确实是高,想穿裙子老师厉害啊,这股钻劲让人佩服。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-22 00:42 , Processed in 0.047126 second(s), 15 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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