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