请教彭兄 前一段时间我也有了解过组合算法,资料上介绍得最多的是回溯和递归,这两种经典算法在解决此类问题上确实是很不错的思路。以前用Javascript写过一个另类的算法,在浏览器里测试的结果要比回溯和递归法快一点。 下面是这个另类算法的代码及思路,不知道为什么在Excel里速度比彭兄设计的两个算法慢多了,我猜是VB的字符串处理效率比较低下。不过我想这个算法可能有用其他技术实现的可能性,效率应该也可以有很大提升的,请彭兄指点一二,谢谢。 Sub yinshe() On Error Resume Next Dim i As Long, m%, n%, aa, str As String aa = Timer With Sheets("sheet1") m = .[A65536].End(xlUp) n = .[B1] End With str = Application.Rept("1", n) & Application.Rept("0", m - n) '生成模拟字符串 Open "d:\peng.txt" For Output As #1 Print #1, extract(str) Do If Right(str, 1) = 0 Then str = Left(str, InStrRev(str, "10") - 1) + Replace(Mid(str, InStrRev(str, "10")), "10", "01") ElseIf InStr(Mid(str, InStrRev(str, "10") + 2), "0") = 0 Then str = Left(str, InStrRev(str, "10") - 1) + Replace(Mid(str, InStrRev(str, "10")), "10", "01") Else str = Left(str, InStrRev(str, "10") - 1) + Replace(Mid(str, InStrRev(str, "10")), "10", "01") str = Left(str, InStrRev(str, "10")) & exchange(Mid(str, InStrRev(str, "10") + 1)) End If Print #1, extract(str) Loop Until Mid(str, InStr(str, "1")) = Application.Rept("1", n) Close #1 MsgBox "找到 " & Application.Combin(m, n) & " 个解! 花费" & Format(Timer - aa, "0.00" & "秒") & "保存在D:\peng.txt" End Sub Function extract(str As String) '提取“1”所在的位置信息 Dim i% extract = "" For i = 1 To Len(str) If Mid(str, i, 1) = 1 Then extract = extract & i & " " End If Next End Function Function exchange(str As String) exchange = Mid(str, InStr(str, "1")) + Left(str, InStr(str, "1") - 1) End Function
算法说明: 以7选4为例,共35组结果: 第一步,生成模拟字符串“1111000”,提取“1”在字符串中的位置就是“1 2 3 4”,即 1111000 1 2 3 4
第二步,从字符串右侧检索第一个“10”,找到后将其位置互换,模拟字符串变成“1110100”,提取“1”在字符串中的位置就是“1 2 3 5” 如此逐步替换,直到字符串最后一个字符不为“0”,即 1110100 1 2 3 5 1110010 1 2 3 6 1110001 1 2 3 7
第三步,当最后一个字符串为“1”时,首先执行第二步,即1101001,然后将最右侧所有连续的“1”插入到倒数第二“1”的后面,即 1101100 1 2 4 5 接下来重复第二步、第三步: 1101010 1 2 4 6 1101001 1 2 4 7 1100101 1100110 1 2 5 6 1100101 1 2 5 7 1100011 1 2 6 7 1010011 1011100 1 3 4 5 1011010 1 3 4 6 1011001 1 3 4 7 1010101 1010110 1 3 5 6 1010101 1 3 5 7 1010011 1 3 6 7 1001011 1001110 1 4 5 6 1001101 1 4 5 7 1001011 1 4 6 7 1000111 1 5 6 7 0100111 0111100 2 3 4 5 0111010 2 3 4 6 0111001 2 3 4 7 0110101 0110110 2 3 5 6 0110101 2 3 5 7 0110011 2 3 6 7 0101011 0101110 2 4 5 6 0101101 2 4 5 7 0101011 2 4 6 7 0100111 2 5 6 7 0010111 0011110 3 4 5 6 0011101 3 4 5 7 0011011 3 4 6 7 0010111 3 5 6 7 判断右侧4位全部为“1”的话,结束 0001111 4 5 6 7
[此贴子已经被作者于2007-12-6 16:18:39编辑过] |