当前位置:编程学习 > VB >>

全组合需要12个小时才能算出45选6的全部组合。有没有办法改进一下运行时间呢。程序代码如下:注意是VFP的,我只会这个编程。

我用VFP设计了一个计算全组合的程序发给大家看看。帮忙改进一下。应为算了一下运行时间,全组合需要12个小时才能算出45选6的全部组合。有没有办法改进一下运行时间呢。程序代码如下:注意是VFP的,我只会这个编程。
CREAT TABLE  ddd(x1 n,X2 N,x3 n,x4 n,x5 n,x6 n)
use ddd

x=45
dimension abs1(x)
for aa=1 to x
   abs1(aa)=aa
endfor

dimension abs2(6)

for a=1 to x
for b=1 to x
if abs1(a)=abs1(b)
loop
endif
for c=1 to x
if abs1(a)=abs1(c) or abs1(b)=abs1(c)
loop
endif
for d=1 to x
if abs1(a)=abs1(d) or abs1(b)=abs1(d) or abs1(c)=abs1(d)
loop
endif
for e=1 to x
if abs1(a)=abs1(e) or abs1(b)=abs1(e) or abs1(c)=abs1(e) or abs1(d)=abs1(e)
loop
endif
for f=1 to x
if abs1(a)=abs1(f) or abs1(b)=abs1(f) or abs1(c)=abs1(f) or abs1(d)=abs1(f) or abs1(e)=abs1(f)
loop
endif

append blank
     replace x1 with caa(1), x2 with caa(2), x3 with caa(3),x4 with caa(4),x5 with caa(5),x6 with caa(6)    
  
endfor
endfor
endfor
endfor
endfor
endfor  --------------------编程问答-------------------- 如果是做彩票程序,建议别做,真没意思!!! --------------------编程问答-------------------- 请高手指教,在线等待 --------------------编程问答-------------------- 跪求啊,小弟不才。想不出更好的改进方法了,运行一次就要12个小时,这不是要命了吗?跪求大虾解救。 --------------------编程问答-------------------- 大虾出手吧,俺等着你们的帮忙。 --------------------编程问答-------------------- 用过递归函数吧,也不知道你怎么算了 要12小时? --------------------编程问答-------------------- 晕,不会VFP啊.楼主尽量多学门语言吧.现在只会VB6都不好混,更别说VFP了 --------------------编程问答-------------------- 此处是                  VB --------------------编程问答-------------------- 算法 :45!/(6!*39!)
本人做个试验45!在非常短的时间就能计算出来。不知道为什么楼主需要12小时。 --------------------编程问答-------------------- Private Sub Command1_Click()'45!
Dim zong  As Double
zong = 1
For i = 1 To 45
zong = zong * i
Next
Text1.Text = zong
End Sub
结果: 1.1962222086548E+56 --------------------编程问答-------------------- 我计算出来的是每个组合,不是算算总有多少个组合。 --------------------编程问答-------------------- 组合这么大的数无论什么算法都是很费时的。
--------------------编程问答-------------------- 一个Button,一个TextBox
1000个中取50个要不了多久.
使用递归的(等有时间弄个C#的)
代码如下:


Option Explicit

Dim m_ResultList() As Integer '结果集
Dim m_SourceList() As Integer '源
Dim m_Count        As Integer  '当前结果集个数
Dim m_SelectCount  As Integer '取数个数
Dim m_MaxCount     As Integer '最大数

'最大数,取数个数
Private Sub Combinations(ByVal MaxCount As Integer, ByVal SelectCount As Integer)

    Dim r As Variant
    Dim i As Integer

    '初始化
    ReDim m_SourceList(MaxCount - 1)
    ReDim m_ResultList(SelectCount - 1)
    m_MaxCount = MaxCount
    m_SelectCount = SelectCount

    For i = 0 To MaxCount - 1
        m_SourceList(i) = i + 1
    Next
    
    m_Count = 0                     '初始化
    r = GetList(m_ResultList)
End Sub

'递归
Private Function GetList(ByRef r As Variant) As Variant

    While m_Count < m_SelectCount

        Dim i As Integer
        Dim j As Integer

        Randomize
        r(m_Count) = CInt(m_MaxCount * Rnd() + 1)   '随机取值,范围为1 ~ m_MaxCount

        For i = 0 To UBound(r)
            For j = 0 To UBound(m_SourceList)
                
                If r(i) = m_SourceList(j) Then
                    m_SourceList(j) = -1        '赋值为-1,标记不再使用
                    m_Count = m_Count + 1   '当前结果集个数+1
                    r = GetList(r)
                End If

            Next
        Next

    Wend

    '检查是否有重复数据所用代码
    '    Dim m          As Integer
    '    Dim n          As Integer
    '    Dim ReaptCount As Integer
    '
    '    For m = 0 To UBound(r) - 1
    '        ReaptCount = 1
    '
    '        For n = 0 To UBound(r) - 1
    '
    '            If r(m) = r(n) Then
    '                If ReaptCount = 2 Then
    '                    MsgBox ("Repeated!")
    '                    GoTo EndLine
    '                End If
    '
    '                ReaptCount = ReaptCount + 1
    '            End If
    '
    '        Next
    '    Next
    '
EndLine:                            GetList = r
End Function

Private Sub cmdCommand1_Click()

    Dim i As Integer

    Combinations 1000, 50   '1000个中取个
    
    txtText1.Text = ""
    For i = 0 To UBound(m_ResultList) - 1
        txtText1.Text = m_ResultList(i) & " " & txtText1.Text
    Next

End Sub


--------------------编程问答--------------------

'获得组合总数
 Private Function Total(ByVal M As Long, ByVal N As Long) As Double
    Dim i As Long
    Dim Result As Double
    Result = 1
    For i = N To 1 Step -1
        Result = Result * M / i
        M = M - 1
    Next
    Total = Result
End Function

Private Sub Command1_Click()
    Debug.Print Total(45, 6)
End Sub

'8145060


上面这个计算出45选6的完全组合为8145060个,如果单单是组合不要求输出结果,全部用long类型,VB的算法(不用递归,递归效率或许更低)估计10秒内可以完成,问题是在于要考虑输出,这样时间会消耗的很厉害....一时想不出好办法... --------------------编程问答-------------------- 不知道楼主弄这个出来有什么意义呢? 难道还准备一一列出来??  --------------------编程问答-------------------- 1.最小是8145060次可以列举出所有组合,还要考虑到随机选取的重复次数

2.不单单是考虑输出,还要考虑判断,因为每次拿出来的组合就要去和已有的组合去对比是否存在,这个判断越到后面消耗越大.最少扫描 8145060 次的判断(存放数据库中).如果不判断,直接保存,就需要进行取重复的操作.
还有要考虑到内存溢出的问题.

在.NET中可以用List<T>不判断直接插入,但是Distinct以及输出时间... ....


引用 13 楼 vbman2003 的回复:
VB code'获得组合总数PrivateFunction Total(ByVal MAsLong, ByVal NAsLong)AsDoubleDim iAsLongDim ResultAsDouble
    Result=1For i= NTo1 Step-1
        Result= Result* M/ i
        M= M-1Next
    Total= ResultEnd FunctionPrivateSub Command1_Click()
    Debug.Print Total(45,6)End Sub'8145060

上面这个计算出45选6的完全组合为8145060个,如果单单是组合不要求输出结果,全部用long类型,VB的算法(不用递归,递归效率或许更低)估计10秒内可以完成,问题是在于要考虑输出,这样时间会消耗的很厉害....一时想不出好办法...
--------------------编程问答-------------------- 代码明显有问题:
⒈ abs2(6) 定义了,但没有使用。
⒉ caa() 没有定义、没有赋值,但却用它来更新数据库的字段。
--------------------编程问答-------------------- 从“目前的”代码来看,你那些 if语句 似乎没有实际意义。
--------------------编程问答-------------------- 高手都在,班门弄斧提一下建议:先遍历所有组合存入数据库,以后每次使用时,随机生成序列号查询数据库。这样一劳永逸,每次操作数据库也快。我自己刚刚写了代码,照我的机器现在运行10分钟已经47万组了,800万组也就3个小时。(不过不清楚楼主的用途,平时随机几组不就行吗?)
Dim i1%, i2%, i3%, i4%, i5%, i6%
For i1 = 1 To 45
    For i2 = 1 To 45
        Do While i2 = i1
        i2 = i2 + 1
        Loop
        For i3 = 1 To 45
            Do While i3 = i1 Or i3 = i2
            i3 = i3 + 1
            Loop
            For i4 = 1 To 45
                Do While i4 = i1 Or i4 = i2 Or i4 = i3
                i4 = i4 + 1
                Loop
                For i5 = 1 To 45
                    Do While i5 = i1 Or i5 = i2 Or i5 = i3 Or i5 = i4
                    i5 = i5 + 1
                    Loop
                    For i6 = 1 To 45
                        Do While i6 = i1 Or i6 = i2 Or i6 = i3 Or i6 = i4 Or i6 = i5
                        i6 = i6 + 1
                        Loop
                        MsgBox i1 & "-" & i2 & "-" & i3 & "-" & i4 & "-" & i5 & "-" & i6 '组合
                    Next i6
                Next i5
            Next i4
        Next i3
    Next i2
Next i1
--------------------编程问答-------------------- ...................路过. --------------------编程问答--------------------
引用 19 楼 myjian 的回复:
...................路过.
路过要指点一下啊,老师。(这么晚还没休息,注意身体) --------------------编程问答-------------------- 你這个是排列,总数是:5,864,443,200 
45选6是组合,总数是:8,145,060

引用 18 楼 skylinecn 的回复:
高手都在,班门弄斧提一下建议:先遍历所有组合存入数据库,以后每次使用时,随机生成序列号查询数据库。这样一劳永逸,每次操作数据库也快。我自己刚刚写了代码,照我的机器现在运行10分钟已经47万组了,800万组也就3个小时。(不过不清楚楼主的用途,平时随机几组不就行吗?)
VB codeDim i1%, i2%, i3%, i4%, i5%, i6%For i1=1To45For i2=1To45DoWhile i2= i1
        i2= i2+1LoopFor i3=1To45DoWhile i3= i1Or i3= i2
            i3= i3+1LoopFor i4=1To45DoWhile i4= i1Or i4= i2Or i4= i3
                i4= i4+1LoopFor i5=1To45DoWhile i5= i1Or i5= i2Or i5= i3Or i5= i4
                    i5= i5+1LoopFor i6=1To45DoWhile i6= i1Or i6= i2Or i6= i3Or i6= i4Or i6= i5
                        i6= i6+1Loop
                        MsgBox i1&"-"& i2&"-"& i3&"-"& i4&"-"& i5&"-"& i6'组合Next i6Next i5Next i4Next i3Next i2Next i1
--------------------编程问答-------------------- 下面的算法在我机器上3秒不到(无输出)...

Option Explicit

'获得组合总数
 Private Function Total(ByVal m As Long, ByVal n As Long) As Long
    Dim i As Long
    Dim Result As Double
    Result = 1
    For i = n To 1 Step -1
        Result = Result * m / i
        m = m - 1
    Next
    Total = Result
End Function

Private Sub CarryComb(CombItem() As Long, pComp() As Long, n As Long)
    Dim i As Long
    i = n
    While CombItem(i) = pComp(i)
        i = i - 1
    Wend
    CombItem(i) = CombItem(i) + 1
    While i < n
        i = i + 1
        CombItem(i) = CombItem(i - 1) + 1
    Wend
End Sub

Private Sub CombResult(m As Long, n As Long, Optional Result As Variant)
    
    Dim i As Long, j As Long
    Dim Num As Long
    
    If n > m Then Exit Sub
    
    ReDim CombItem(1 To n) As Long
    ReDim pComp(1 To n) As Long
    
    Num = m - n
    For i = 1 To n - 1
        CombItem(i) = i
        pComp(i) = Num + i
    Next
    CombItem(n) = n - 1
    pComp(n) = m
    
    Num = Total(m, n)   ': Debug.Print Num
    'ReDim Result(1 To Num)
    For i = 1 To Num
        CarryComb CombItem, pComp, n
        'Result(i) = CombItem
        'DoEvents
    Next
    Result = CombItem   '最后一个组合结果
End Sub

'输出单个组合结果
Private Sub PrintComb(CombItem, n As Long)
    Dim i As Long
    For i = 1 To n
        Debug.Print CombItem(i);
    Next
    Debug.Print
End Sub

Private Sub Command1_Click()
    
    Dim m As Long, n As Long
    Dim myResult
    Dim t As Double

    t = Timer
    m = 45
    n = 6
    Call CombResult(m, n, myResult)
    'Debug.Print Join(myResult, vbCrLf)
    Debug.Print Timer - t
    
    Call PrintComb(myResult, n)  '验证最后一个组合
    
End Sub


理论上,在一定规则下,应该可以实现指定第x个组合,不用循环直接得到第x个组合的结果,也可以由一个组合结果得到是第几个组合...等没事时,有兴趣的话再研究下.... --------------------编程问答-------------------- 谢谢21楼老师提醒,确实存在漏洞,呵呵。我修改一下,没详测,请老师们空了指点。
Private Sub Command1_Click()
Dim i1%, i2%, i3%, i4%, i5%, i6%
For i1 = 1 To 45
    For i2 = 1 To 45
        Do While i2 = i1
        i2 = i2 + 1: If i2 > 45 Then Exit For
        Loop
        For i3 = 1 To 45
            Do While i3 = i1 Or i3 = i2
            i3 = i3 + 1: If i3 > 45 Then Exit For
            Loop
            For i4 = 1 To 45
                Do While i4 = i1 Or i4 = i2 Or i4 = i3
                i4 = i4 + 1: If i4 > 45 Then Exit For
                Loop
                For i5 = 1 To 45
                    Do While i5 = i1 Or i5 = i2 Or i5 = i3 Or i5 = i4
                    i5 = i5 + 1: If i5 > 45 Then Exit For
                    Loop
                    For i6 = 1 To 45
                        Do While i6 = i1 Or i6 = i2 Or i6 = i3 Or i6 = i4 Or i6 = i5
                        i6 = i6 + 1: If i6 > 45 Then Exit For
                        Loop
                        MsgBox i1 & "-" & i2 & "-" & i3 & "-" & i4 & "-" & i5 & "-" & i6 '组合
                      Next i6
                Next i5
            Next i4
        Next i3
    Next i2
Next i1
End Sub
--------------------编程问答--------------------
引用 22 楼 vbman2003 的回复:
下面的算法在我机器上3秒不到(无输出)...
VB codeOptionExplicit'获得组合总数PrivateFunction Total(ByVal mAsLong, ByVal nAsLong)AsLongDim iAsLongDim ResultAsDouble
    Result=1For i= nTo1 Step-1
        Result= Result* m/ i
        m= m-1Next
    Total= ResultEnd FunctionPrivateSub CarryComb(CombItem()AsLong, pComp()AsLong, nAsLong)Dim iAsLong
    i= nWhile CombItem(i)= pComp(i)
        i= i-1Wend
    CombItem(i)= CombItem(i)+1While i< n
        i= i+1
        CombItem(i)= CombItem(i-1)+1WendEnd SubPrivateSub CombResult(mAsLong, nAsLong, Optional ResultAs Variant)Dim iAsLong, jAsLongDim NumAsLongIf n> mThenExitSubReDim CombItem(1To n)AsLongReDim pComp(1To n)AsLong
    
    Num= m- nFor i=1To n-1
        CombItem(i)= i
        pComp(i)= Num+ iNext
    CombItem(n)= n-1
    pComp(n)= m
    
    Num= Total(m, n)': Debug.Print Num'ReDim Result(1 To Num)For i=1To Num
        CarryComb CombItem, pComp, n'Result(i) = CombItem'DoEventsNext
    Result= CombItem'最后一个组合结果End Sub'输出单个组合结果PrivateSub PrintComb(CombItem, nAsLong)Dim iAsLongFor i=1To n
        Debug.Print CombItem(i);Next
    Debug.PrintEnd SubPrivateSub Command1_Click()Dim mAsLong, nAsLongDim myResultDim tAsDouble

    t=Timer
    m=45
    n=6Call CombResult(m, n, myResult)'Debug.Print Join(myResult, vbCrLf)    Debug.PrintTimer- tCall PrintComb(myResult, n)'验证最后一个组合End Sub

理论上,在一定规则下,应该可以实现指定第x个组合,不用循环直接得到第x个组合的结果,也可以由一个组合结果得到是第几个组合...等没事时,有兴趣的话再研究下....
哇,高手,学习了。先上班待会再来请教老师。 --------------------编程问答-------------------- 如果仅仅是输出所有组合(跟随机数没关的话),不需要那么多多余的代码
下面的代码,把所有的组合都输出
输出是调用API的,每次输出2000组结果到txt,如果不调用API代码更少,只是会慢些
(应该还有更快的方法输出,直接操作数组,不用string)

目前大概51分钟,txt档案 130Mb左右



Const GENERIC_WRITE = &H40000000

 Const GENERIC_READ = &H80000000

 Const FILE_ATTRIBUTE_NORMAL = &H80

 Const CREATE_ALWAYS = 2

 Const OPEN_ALWAYS = 4

 Const INVALID_HANDLE_VALUE = -1

Private Declare Function WriteFile _
               Lib "kernel32" (ByVal hFile As Long, _
                               ByVal lpBuffer As String, _
                               ByVal nNumberOfBytesToWrite As Long, _
                               lpNumberOfBytesWritten As Long, _
                               ByVal lpOverlapped As Long) As Long

Private Declare Function CreateFile _
               Lib "kernel32" _
               Alias "CreateFileA" (ByVal lpFileName As String, _
                                    ByVal dwDesiredAccess As Long, _
                                    ByVal dwShareMode As Long, _
                                    ByVal lpSecurityAttributes As Long, _
                                    ByVal dwCreationDisposition As Long, _
                                    ByVal dwFlagsAndAttributes As Long, _
                                    ByVal hTemplateFile As Long) As Long

Private Declare Function FlushFileBuffers Lib "kernel32" (ByVal hFile As Long) As Long


Private Sub cmdCommand3_Click()

    Dim i1            As Integer, i2 As Integer, i3 As Integer, i4 As Integer, i5 As Integer, i6 As Integer
    Dim lCount        As Long
    Dim strResult     As String
    Dim fHandle       As Long
    Dim fSuccess      As Long
    Dim lBytesWritten As Long
    Dim BytesToWrite  As Long
    Dim BeginTime     As Date
    Dim EndTime       As Date
    Dim TotalCount    As Double

    BeginTime = Now

    If Dir("d:\1.txt") <> "" Then Kill ("d:\1.txt")
    
    fHandle = CreateFile("d:\1.txt", GENERIC_WRITE Or GENERIC_READ, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)


    If fHandle = INVALID_HANDLE_VALUE Then
        CloseHandle (fHandle)

        Exit Sub

    End If

    For i1 = 1 To 45
        For i2 = 1 To 45

            If i2 = i1 Then Exit For

            For i3 = 1 To 45

                If i3 = i2 Or i3 = i1 Then Exit For

                For i4 = 1 To 45

                    If i4 = i3 Or i4 = i2 Or i4 = i1 Then Exit For

                    For i5 = 1 To 45

                        If i5 = i4 Or i5 = i3 Or i5 = i2 Or i5 = i1 Then Exit For

                        For i6 = 1 To 45

                            If i6 = i5 Or i5 = i4 Or i5 = i3 Or i5 = i2 Or i5 = i1 Then Exit For
                            strResult = strResult & i1 & "-" & i2 & "-" & i3 & "-" & i4 & "-" & i5 & "-" & i6 & " "
                            lCount = lCount + 1
                            TotalCount = TotalCount + 1

                            '每个结果输出一次到文本
                            If lCount = 2000 Then
                                '取得字符串长度
                                BytesToWrite = Len(strResult)
                                fSuccess = WriteFile(fHandle, strResult, BytesToWrite, lBytesWritten, 0)

                                '是否写入成功
                                If fSuccess <> 0 Then
                                    '强制输出缓存
                                    fSuccess = FlushFileBuffers(fHandle)
                                End If

                                '清空结果
                                strResult = ""
                                lCount = 0
                            End If

                        Next
                    Next
                Next
            Next
        Next
    Next

    CloseHandle (fHandle)

    EndTime = Now

    MsgBox ("Time: " & DateDiff("n", BeginTime, EndTime) & " Count:" & TotalCount)
End Sub

引用 23 楼 skylinecn 的回复:
谢谢21楼老师提醒,确实存在漏洞,呵呵。我修改一下,没详测,请老师们空了指点。VB codePrivateSub Command1_Click()Dim i1%, i2%, i3%, i4%, i5%, i6%For i1=1To45For i2=1To45DoWhile i2= i1
        i2= i2+1:If i2>45ThenExitForLoopFor i3=1To45DoWh?-
--------------------编程问答-------------------- 输入多个txt文本中...1分钟多点.....

Option Explicit

'获得组合总数
 Private Function Total(ByVal m As Long, ByVal n As Long) As Long
    Dim i As Long
    Dim Result As Double
    Result = 1
    For i = n To 1 Step -1
        Result = Result * m / i
        m = m - 1
    Next
    Total = Result
End Function

Private Sub CarryComb(CombItem, pComp() As Long, n As Long)
    Dim i As Long
    i = n
    While CombItem(i) = pComp(i)
        i = i - 1
    Wend
    CombItem(i) = CombItem(i) + 1
    While i < n
        i = i + 1
        CombItem(i) = CombItem(i - 1) + 1
    Wend
End Sub

Private Sub CombResult(m As Long, n As Long, Optional Result As Variant)
    
    Dim i As Long, j As Long
    Dim Num As Long
    Dim Idx As Long
    Dim h As Long
    Const Length = 100000    '每个文本的组合个数
    
    If n > m Then Exit Sub
    
    ReDim CombItem(1 To n)
    ReDim pComp(1 To n) As Long
    
    Num = m - n
    For i = 1 To n - 1
        CombItem(i) = i
        pComp(i) = Num + i
    Next
    CombItem(n) = n - 1
    pComp(n) = m
    
    Num = Total(m, n)   ': Debug.Print Num
    ReDim Result(1 To Length)
    For i = 1 To Num
        CarryComb CombItem, pComp, n
        Idx = Idx + 1
        Result(Idx) = Join(CombItem)
        If Idx = Length Then
            Idx = 0
            h = FreeFile
            Open "D:\comb" & i & ".txt" For Binary As h
                Put #h, , Join(Result, vbCrLf)
            Close
            ReDim Result(1 To Length)
        End If
        'DoEvents
    Next
    Open "D:\comb" & i & ".txt" For Binary As h
        Put #h, , Join(Result, vbCrLf)
    Close
End Sub


Private Sub Command1_Click()
    
    Dim m As Long, n As Long
    Dim t As Double

    t = Timer
    m = 45
    n = 6
    Call CombResult(m, n)
    Debug.Print Timer - t
    
End Sub

--------------------编程问答-------------------- 上的计算用了Variant,与long相比,速度慢了许多....没时间深究了,算是个思路吧....
补充:VB ,  基础类
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,