随机凑数


Sub test()
    tms = Timer
    h = [e2] '目标和值h
    g = [g2] '凑数计算精度g 即Round函数的第2参数位数指定
    m = [a1].End(4).Row - 1 '有效元素个数m
    ar = [a2].Resize(m, 2)
    For i = 1 To m
        ar(i, 1) = i
    Next
    [b2].Resize(m).Sort [b2], 1, , , , , , 2 '数据排序
    br = [b2].Resize(m)
    s = h
    For i = m To 1 Step -1
        If br(i, 1) < s Then n1 = n1 + 1: s = s - br(i, 1) Else n1 = n1 + 1: [i4] = n1: Exit For '最少个数n1
    Next
    s = h
    For i = 1 To m
        If br(i, 1) < s Then s = s - br(i, 1) Else n2 = i - 1: [j4] = n2: Exit For '最多个数n2
    Next
    [a2].Resize(m, 2) = ar
    [c2].Resize(m) = ""
    [g4] = ""
Redo:
    cnt = 0: [g4] = [g4] + 1
    n = [e4] '指定个数n
    If n = 0 Then n = m Else If [g4] > 10 Then n = m Else If n < n1 Or n > n2 Then n = m
    '不指定n时、或随机次数超过10次仍未算出结果时、或指定n超允许范围n1,n2时:一律改为个数随机不指定。
    s = h
    Randomize
    For i = 1 To n '随机洗牌指定次数n、或接近目标值时停止
        r = Int(Rnd * (m - i + 1)) + i
        If n = m Then If s < ar(r, 2) Then n = i - 1: Exit For
        t = ar(r, 1): ar(r, 1) = ar(i, 1): ar(i, 1) = t
        t = ar(r, 2): ar(r, 2) = ar(i, 2): ar(i, 2) = t
        s = s - t
    Next
    Do While Int(s * 10 ^ g) '随机交换直至误差<0.5*10^-g时 g=1是<0.05时
        cnt = cnt + 1
        '        If cnt Mod 1000 = 0 Then DoEvents
        If cnt > 10000 Then GoTo Redo '万次随机无果时重新做
        i = Int(Rnd * n) + 1
        r = Int(Rnd * (m - n)) + n + 1
        s1 = s + ar(i, 2) - ar(r, 2)
        If Abs(s1) < Abs(s) Then '差值更小时,随机交换
            t = ar(i, 1): ar(i, 1) = ar(r, 1): ar(r, 1) = t
            t = ar(i, 2): ar(i, 2) = ar(r, 2): ar(r, 2) = t
            s = s + t - ar(i, 2)
        End If
    Loop
    '    Debug.Print cnt '计算完成
    '本打算对随机结果进行1对1的组合微调,但效果不明显。
    '    For i = 1 To n
    '        For r = n + 1 To m
    '            If s = ar(r, 2) - ar(i, 2) Then
    '                t = ar(i, 1): ar(i, 1) = ar(r, 1): ar(r, 1) = t
    '                t = ar(i, 2): ar(i, 2) = ar(r, 2): ar(r, 2) = t
    '                Stop
    '                Exit For
    '            End If
    '        Next
    '        If r <= m Then Exit For
    '    Next
    [h4] = Format(Timer - tms, "0.000s")
    ReDim cr(1 To m, 1 To 1) '输出结果
    s = 0
    For i = 1 To n
        s = s + ar(i, 2)
        cr(ar(i, 1), 1) = 1
        '        Cells(ar(i, 1) + 1, 3) = 1
    Next
    [c2].Resize(m) = cr
    MsgBox "本次差值: " & s - h
End Sub

 

 

 

posted @ 2022-11-22 08:52  依云科技  阅读(83)  评论(0)    收藏  举报