我不知道正确的名称是“平衡”。
我有一个2n正整数元素的数组,我想分成两个n元素数组,它们的平均值之间的差异最小。例如:
values: {4, 4, 7, 8, 10, 15}
(some magic here)
a: {7, 8, 10}
b: {4, 4, 15}
我不确定是否总是将最小的数字与最大的数字组合在一起会将不同的平均值分开。有没有办法实现这个算法总是正确分裂?
答案 0 :(得分:0)
如果我理解你的需要,一个快速且近似正确的解决方案是:
如果您的要求允许,关键是对原始数组进行排序,或者创建一个新的“原始”数组,如果不允许就地排序,则该数组是真实原始数组的排序副本。
如果N相当大并且数字的分布相当均匀(例如,没有朝向一端或另一端的大偏斜),则该解决方案将非常接近理想解决方案。
如果你真的要求平均值尽可能彼此接近,即使数字有很大的偏差,我能想到的唯一方法是尝试每一个排列并保持最小差异的一个。平均。
答案 1 :(得分:0)
local function some_magic(V)
assert(#V % 2 == 0 and #V > 0)
table.sort(V)
local S = {[-1] = math.huge, [0] = 0}
for i = 1, #V do
S[i] = S[i-1] + V[i]
end
local half_sum = math.floor(S[#V] / 2)
local half_len = #V / 2
local m = 2^math.ceil(math.log(half_len+1)/math.log(2))
local P = {[0] = 0}
for idx = #V, 1, -1 do
local v, P2 = V[idx], {}
for k in pairs(P) do
if math.floor(k/m) + v + S[half_len - k%m - 1] <= half_sum then
P2[k + v*m + 1] = idx
end
end
for k, v in pairs(P2) do
P[k] = P[k] or v
end
end
local k = 0
for next_k in pairs(P) do
if next_k > k and next_k%m == half_len then
k = next_k
end
end
local A, B, prev_idx = {}, {}, 0
repeat
local idx = P[k]
for i = prev_idx + 1, idx - 1 do
table.insert(B, V[i])
end
table.insert(A, V[idx])
prev_idx = idx
k = k - V[idx]*m - 1
until k == 0
for i = prev_idx + 1, #V do
table.insert(B, V[i])
end
return A, B
end
local values = {4, 4, 7, 8, 10, 15}
print('values: '..table.concat(values, ','))
local a, b = some_magic(values)
print('a: '..table.concat(a, ','))
print('b: '..table.concat(b, ','))
------------- Output: ------------
values: 4,4,7,8,10,15
a: 4,4,15
b: 7,8,10