我具有非负值的阵列。 我想建立数值数组谁的总和为20,使它们成正比的第一阵列。
这将是一个简单的问题,但我想比例阵列总结正好20,补偿任何舍入误差。
例如,该阵列
input = [400, 400, 0, 0, 100, 50, 50]
将产生
output = [8, 8, 0, 0, 2, 1, 1]
sum(output) = 20
然而,大多数情况下,将会有大量的舍入误差,如
input = [3, 3, 3, 3, 3, 3, 18]
天真地产生
output = [1, 1, 1, 1, 1, 1, 10]
sum(output) = 16 (ouch)
有没有分摊输出数组,这样加起来,以每次20的好办法?
Answer 1:
有一个很简单的回答了这个问题:我已经做了很多次。 每个分配到新的数组后,可以减少你使用如下工作的值:
- 调用第一阵列A,和新的,比例阵列B(其中开始是空的)。
- 呼叫的元件T的总和
- 调用期望的总和S.
- 对于阵列(ⅰ)执行以下操作中的每个元素:
一个。 B [I] =圆(A [I] / T * S)。 (四舍五入至最接近的整数,便士或任何是必需的)
湾 T = - A [1]
C。 S =的S - B [i]于
而已! 易溶于任何编程语言或电子表格来实现。
该解决方案是最佳的,所述得到的数组的元素将不会超过1远离他们的理想的,非圆形的值。 让我们与你的实例来说明:
T = 36,S = 20 B [1] =圆(A [1] / T * S)= 2(理想地,1.666 ....)
T = 33,S = 18,B [2] =圆(A [2] / T * S)= 2(理想地,1.666 ....)
T = 30,S = 16,B [3] =圆(A [3] / T * S)= 2(理想地,1.666 ....)
T = 27,S = 14,B [4] =圆(A [4] / T * S)= 2(理想地,1.666 ....)
T = 24,S = 12,B [5] =圆(A [5] / T * S)= 2(理想地,1.666 ....)
T = 21,S = 10,B [6] =圆(A [6] / T * S)= 1(理想地,1.666 ....)
T = 18,S = 9 B [7] =圆(A [7] / T * S)= 9(理想地,10)
请注意,每个值B中与之比较的理想值在括号中,不同的是从来没有超过1。
这也是有趣的是,重新安排数组中的元素可能导致所得数组中不同的相应的值。 我发现,按升序排列的元素是最好的,因为它会导致实际与理想之间的最小平均差异。
Answer 2:
你的问题是类似比例代表要分享当事人proportionnaly他们获得的选票中的N个席位(在你的案件20),你的情况[3,3,3,3,3,3,18]
有在不同国家用于处理四舍五入问题的几种方法。 我的代码下面使用哈根巴赫-Bischoff的配额在瑞士,使用的方法基本上由分配(N + 1)的整数除法,其具有最高的剩余各方之后剩余的席位:
def proportional(nseats,votes):
"""assign n seats proportionaly to votes using Hagenbach-Bischoff quota
:param nseats: int number of seats to assign
:param votes: iterable of int or float weighting each party
:result: list of ints seats allocated to each party
"""
quota=sum(votes)/(1.+nseats) #force float
frac=[vote/quota for vote in votes]
res=[int(f) for f in frac]
n=nseats-sum(res) #number of seats remaining to allocate
if n==0: return res #done
if n<0: return [min(x,nseats) for x in res] # see siamii's comment
#give the remaining seats to the n parties with the largest remainder
remainders=[ai-bi for ai,bi in zip(frac,res)]
limit=sorted(remainders,reverse=True)[n-1]
#n parties with remainter larger than limit get an extra seat
for i,r in enumerate(remainders):
if r>=limit:
res[i]+=1
n-=1 # attempt to handle perfect equality
if n==0: return res #done
raise #should never happen
但是这种方法并不总是产生相同数目的席位与在你的情况下,完全平等方:
proportional(20,[3, 3, 3, 3, 3, 3, 18])
[2,2,2,2,1,1,10]
Answer 3:
您已设置3项不兼容的要求。 一个整数值阵列成正比[1,1,1]
不能进行总结准确20.你必须选择突破“正好20总和”之一的,“成比例的输入”和“整数值”的要求。
如果你选择打破了整数值的要求,然后用浮点或有理数。 如果你选择打破确切数额的要求,那么你已经解决了这个问题。 选择打破比例是有点麻烦。 你可能会采取一种办法是要弄清楚如何遥远的总和,然后通过输出数组随机分配更正。 例如,如果你输入的是:
[1, 1, 1]
那么你可以先让它总结以及可能的,同时仍然比例:
[7, 7, 7]
并且由于20 - (7+7+7) = -1
,选择一种元素随机递减:
[7, 6, 7]
如果错误是4
,你会选择四个元素递增。
Answer 4:
不执行良好,但会提供正确的结果天真的解决方案...
写该给定的阵列具有八个整数(一个迭代candidate
)和input
阵列,输出是最远离正比于其他人(伪码)的元素的索引:
function next_index(candidate, input)
// Calculate weights
for i in 1 .. 8
w[i] = candidate[i] / input[i]
end for
// find the smallest weight
min = 0
min_index = 0
for i in 1 .. 8
if w[i] < min then
min = w[i]
min_index = i
end if
end for
return min_index
end function
然后,只是这样做
result = [0, 0, 0, 0, 0, 0, 0, 0]
result[next_index(result, input)]++ for 1 .. 20
如果没有最佳的解决方案,它会扭曲对数组的开始。
使用上面的方法,你可以舍去(如你在你的例子一样),然后只用上面的方法来补充是要被抛弃了,由于舍入误差减少迭代次数:
result = <<approach using rounding down>>
while sum(result) < 20
result[next_index(result, input)]++
Answer 5:
因此,上述问题的答案和意见是有益的......特别是从@Frederik下降和评论。
我想出了溶液利用这样的事实,对于一个输入数组V,总和(V_I * 20)是由总和(V)整除的优势。 因此,对于V中的每个值,我mulitply 20,以及将和数鸿沟。 我把商,积累剩余。 每当累加器比总和(V)时,我添加一个到值。 这样的话,我保证所有的余得到滚入结果。
是清晰? 下面是用Python实现:
def proportion(values, total):
# set up by getting the sum of the values and starting
# with an empty result list and accumulator
sum_values = sum(values)
new_values = []
acc = 0
for v in values:
# for each value, find quotient and remainder
q, r = divmod(v * total, sum_values)
if acc + r < sum_values:
# if the accumlator plus remainder is too small, just add and move on
acc += r
else:
# we've accumulated enough to go over sum(values), so add 1 to result
if acc > r:
# add to previous
new_values[-1] += 1
else:
# add to current
q += 1
acc -= sum_values - r
# save the new value
new_values.append(q)
# accumulator is guaranteed to be zero at the end
print new_values, sum_values, acc
return new_values
(I补充说,如果累加器>其余部分,我递增先前值代替当前值的增强)
文章来源: Allocate an array of integers proportionally compensating for rounding errors