Excel精英培训网

 找回密码
 注册
数据透视表40+个常用小技巧,让你一次学会!
查看: 8872|回复: 10

[已解决]怎样用递归法显示出所有组合数问题

[复制链接]
发表于 2013-6-28 09:16 | 显示全部楼层 |阅读模式
怎样用递归法显示出所有组合数问题.zip (9.33 KB, 下载次数: 88)
excel精英培训的微信平台,每天都会发送excel学习教程和资料。扫一扫明天就可以收到新教程
发表于 2013-6-28 10:37 | 显示全部楼层
排列组合不需要递归。论坛有相关讨论帖。自己搜下吧。
回复

使用道具 举报

 楼主| 发表于 2013-6-28 23:19 | 显示全部楼层
回复

使用道具 举报

 楼主| 发表于 2013-6-30 06:43 | 显示全部楼层
再发求助请求。
回复

使用道具 举报

发表于 2013-7-1 15:28 | 显示全部楼层
递归可以有。

如果就是 1-372 构成的31组12位数字进行31取6组合=736281组解的话,
用下面递归代码计算只要 30秒以内。
但73万多行结果输出到工作表就可能耗费大量时间了。→ 或许会死机?我没有试。
  1. Dim sj%(), jg%(), l%, m%, n%, k&
  2. Sub 組合()
  3.     tms = Timer
  4.     m = 31: n = 6: l = 12
  5.     ReDim sj%(1 To m, 1 To l)
  6.     For i = 1 To m
  7.         For j = 1 To l
  8.             k = k + 1
  9.             sj(i, j) = k
  10.         Next
  11.     Next
  12.    
  13.     k = WorksheetFunction.Combin(m, n)
  14.     ReDim jg%(1 To k, 1 To n * l)
  15.     k = 0: Call dgZH("", 0, 1)
  16.    
  17.     MsgBox Format(Timer - tms, "0.000s ") & k: tms = Timer
  18.     [a1].Resize(Rows.Count, n * l) = ""
  19.     [a1].Resize(k, n * l) = jg
  20.     MsgBox Format(Timer - tms, "0.000s ")
  21. End Sub
  22. Sub dgZH(s$, i%, t%)
  23.     Dim j%, ii%, jj%
  24.     For j = i + 1 To m
  25.         If t < n Then
  26.             Call dgZH(s & j & ",", j, t + 1)
  27.         Else
  28.             k = k + 1
  29.             p = Split(s & j, ",")
  30.             For ii = 0 To UBound(p)
  31.                 For jj = 1 To l
  32.                     jg(k, ii * l + jj) = sj(p(ii), jj)
  33.                 Next
  34.             Next
  35.         End If
  36.     Next
  37. '    Application.StatusBar = s
  38. End Sub
复制代码
回复

使用道具 举报

发表于 2013-7-1 15:33 | 显示全部楼层
wcymiss 发表于 2013-6-28 10:37
排列组合不需要递归。论坛有相关讨论帖。自己搜下吧。

吴姐你好!


经过改进,目前EXCEL VBA代码中,我的Do……Loop循环计算组合的代码速度效率最好!
  1. Sub Combin_kagawa(m&, n&)
  2. tms = Timer
  3. Dim i&, j&, l1&
  4. ReDim a&(1 To n)
  5. If n = m Then For j = 2 To n - 1: a(j) = j: Next

  6. a(n) = m: a(1) = 0: j = 1: l1 = m - n + 1
  7. Do
  8.   If a(n) = m Then
  9.     a(j) = a(j) + 1
  10.     If a(j) < m - n + j Then
  11.       For j = j To n - 1
  12.         a(j + 1) = a(j) + 1
  13.       Next
  14.     End If
  15.     j = j - 1
  16.   Else
  17.     a(n) = a(n) + 1
  18.   End If
  19.   i = i + 1
  20. Loop While a(1) < l1 'm - n + 1
  21. Cells(n, 6) = Format(Timer - tms, " 0.000s") & " kagawa Combin(" & m & "," & n & ")= " & Application.Combin(m, n)
  22. End Sub
复制代码

点评

吴姐 这么隐蔽都被你发现了!!!!  发表于 2013-7-7 06:32
回复

使用道具 举报

发表于 2013-7-1 16:18 | 显示全部楼层
本帖最后由 香川群子 于 2013-7-7 21:01 编辑

呵呵,用我香川发明的Do……Loop循环计算组合,只要5秒以内啊!
比递归快了5-6倍。
  1. Sub Combin_kagawa()
  2.     tms = Timer
  3.     Dim i&, j&, l1&, ii&, jj&, l&, m&, n&, t&
  4.     m = 31: n = 6: l = 12
  5.    
  6.     ReDim sj%(1 To m, 1 To l)
  7.     For i = 1 To m
  8.         For j = 1 To l
  9.             k = k + 1
  10.             sj(i, j) = k
  11.         Next
  12.     Next
  13.    
  14.     i = WorksheetFunction.Combin(m, n)
  15.     ReDim jg%(1 To i, 1 To n * l)
  16.    
  17.     ReDim a&(1 To n)
  18.     a(n) = m: a(1) = 0
  19.     i = 0: j = 1: l1 = m - n + 1
  20.     Do
  21.         If a(n) = m Then
  22.             a(j) = a(j) + 1
  23.             If a(j) < m - n + j Then
  24.                 For j = j To n - 1
  25.                     a(j + 1) = a(j) + 1
  26.                 Next
  27.             End If
  28.             j = j - 1
  29.         Else
  30.             a(n) = a(n) + 1
  31.         End If
  32.         '以上为生成各种组合变化
  33.         i = i + 1 '下面为输出组合结果部分
  34.         For ii = 0 To n - 1
  35.             For jj = 1 To l
  36.                 jg(i, ii * l + jj) = sj(a(ii + 1), jj)
  37.             Next
  38.         Next
  39.     Loop While a(1) < l1 'm - n + 1
  40.    
  41.     MsgBox Format(Timer - tms, "0.000s"): tms = Timer
  42.     'Erase jg: Exit Sub '不输出结果就结束

  43.     '应楼主要求,改为从B9单元格开始输出结果
  44.     [b9].Resize(Rows.Count - 9, n * l) = ""
  45.     [b9].Resize(k, n * l) = jg
  46.     MsgBox Format(Timer - tms, "0.000s")
  47. End Sub

复制代码
应楼主要求,改为从B9单元格开始输出结果
回复

使用道具 举报

发表于 2013-7-1 16:33 | 显示全部楼层
其实不包含输出部分,仅仅组合计算Combin(31,6)=736281时,
香川的Do……Loop循环只要0.2秒就计算完成了。

递归的时间是0.3秒……可是因为输出结果时使用了split方法,所以慢了很多。
或许改为用数组a()存储状态会好很多。


回复

使用道具 举报

发表于 2013-7-1 16:48 | 显示全部楼层    本楼为最佳答案   
本帖最后由 香川群子 于 2013-7-7 21:00 编辑

呵呵,递归也改用数组a()记录组合状态以后,速度也提高到7秒以内……
  1. Dim sj%(), jg%(), l%, m%, n%, k&
  2. Sub 递归组合()
  3.     tms = Timer
  4.     m = 31: n = 6: l = 12: k = 0
  5.     ReDim sj%(1 To m, 1 To l)
  6.     For i = 1 To m
  7.         For j = 1 To l
  8.             k = k + 1
  9.             sj(i, j) = k
  10.         Next
  11.     Next
  12.    
  13.     ReDim a&(n - 1)
  14.     k = WorksheetFunction.Combin(m, n)
  15.     ReDim jg%(1 To k, 1 To n * l)
  16.     k = 0: Call dgZH(a, 0, 0)
  17.     MsgBox Format(Timer - tms, "0.000s"): tms = Timer
  18.     'Erase jg: Exit Sub '不输出结果直接停止

  19.    '应楼主要求,改为从B9单元格开始输出结果
  20.     [b9].Resize(Rows.Count -9, n * l) = ""
  21.     [b9].Resize(k, n * l) = jg
  22.     MsgBox Format(Timer - tms, "0.000s")
  23. End Sub
  24. Sub dgZH(a&(), i%, t%)
  25.     Dim j%, ii%, jj%
  26.     For j = i + 1 To m
  27.         If t + 1 < n Then
  28.             a(t) = j
  29.             Call dgZH(a(), j, t + 1)
  30.         Else
  31.             k = k + 1
  32.             a(t) = j
  33.             For ii = 0 To n - 1
  34.                 For jj = 1 To l
  35.                     jg(k, ii * l + jj) = sj(a(ii), jj)
  36.                 Next
  37.             Next
  38.         End If
  39.     Next
  40. End Sub
复制代码
应楼主要求,改为从B9单元格开始输出结果
回复

使用道具 举报

 楼主| 发表于 2013-7-2 01:14 | 显示全部楼层
香川群子 发表于 2013-7-1 16:48
呵呵,递归也改用数组a()记录组合状态以后,速度也提高到7秒以内……

谢谢群子老师的帮助!编写vba代码又给论坛里的朋友们总结出更快捷、简便的方法,认真学习、测试过程中还希望通过这道题能像论坛中的高手学习更多。再次谢谢!
回复

使用道具 举报

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

本版积分规则

小黑屋|手机版|Archiver|Excel精英培训 ( 豫ICP备11015029号 )

GMT+8, 2024-4-25 08:21 , Processed in 0.591517 second(s), 11 queries , Gzip On, Yac On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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