我正在寻找一个快速(在复杂性方面(问题的大小可能接近2 ^ 32)和在常数方面),这不一定要计算最优解(因此,如果一种启发式方法产生的结果“接近”最优并且在计算特定问题的计算时间方面具有“相当大的”优势,那么启发式是可接受的。
我有一个整数直方图A:|A| = n, A[i]>0
;和值R:0<R<=A[0]+...+A[n-1]
。我必须尽可能均匀地在直方图上分配-R。形式上这意味着这样的事情(在正式表示法中也有一些额外的信息):我需要找到B,这样|B| = |A| && B[i] = A[i] - C[i]
,其中0<=C[i]<=A[i] && C[0]+...+C[n-1] = R
和C必须最小化表达式:{{1} }和L_2 = C[0]^2 + ... + C[n-1]^2
。只需从公式中可以看出问题不一定具有唯一解(考虑A [0] = 1,A [1] = 1且R = 1,则B [0] = 0,B [1] ] = 1且B'[0] = 1,B'[1] = 0是最优解),可以添加一个附加约束,例如L_infinity = max(C[0], ..., C[n-1])
,但在我的情况下它并不重要。天真的人可以迭代C [i]的所有可能性(R-重复组合)并找到最优解,但显然对于较大的n并不是非常快。
另一种可能的解决方案是找到if A[i]<A[j] then C[i]<C[j]
和q = R/n
,然后迭代所有元素并存储r=R%n
,diff[i] = A[i]-q
,然后继续所有未删除的A [i] ,将它们设置为if diff[i]<=0 then r-=diff[i] && B[i] = 0 && remove A[i]
,A[i] = diff[i]
和R = r
。如果迭代这个过程,那么在每个步骤我们将删除至少一个元素,直到我们到达n=n-removedElementsCount
或我们只有1个元素的点,然后我们只需要{R}这样q == 0
来自A的元素,因为在A[i]-=1
情况下是R<n
,或者只有q==0
,如果我们只有1个元素剩余(我们有0个元素的情况是不重要的)。由于我们每步删除至少一个元素,并且我们需要在最坏的情况下迭代A[i]-=R
个元素,然后我们的复杂度为O((1 + ... + n))= O(n ^ 2)。
我希望有人已经熟悉一个更好的算法,或者如果你有任何想法我会很高兴听到它们(我知道这也可以被认为是一个优化问题)。
编辑:使R为正,因此更容易阅读。
编辑2:我意识到我搞砸了优化标准。
答案 0 :(得分:1)
将直方图转换为(value, index)
对数组,然后将其转换为min heap。此操作为O(n)
。
现在,您的C
会将一些值设置为0
,将最大值减少一些,其余值减去最大值1。您喜欢减少所有内容的最大金额很容易计算,它被R/n
四舍五入。
现在通过堆。只要堆底部的值为< ceil(R/size of heap)
,该索引处的该值将设置为零,并在时间O(log(n))
中从堆中删除该值。一旦该循环结束,您可以将最大值和小于最大值的1分配给其余部分。
这将在O(n log(n))
最糟糕的时间运行。当必须将O(n)
元素清零时,您将遇到最糟糕的情况。
答案 1 :(得分:0)
我在O(n * log(n))时间内想出了一个非常简单的贪婪算法(如果有人设法在O(n)中解决它,尽管我很乐意听到)。
算法:
给定:整数数组:A[0],...,A[|A|-1]: A[i]>=0
;整数:R0: 0<=R0<=A[0]+...+A[|A|-1]
。
基地:
按升序排序 - 取O(n * log(n)时间。
设置i = 0; R = R0; n = |A|; q = floor(R/n); r = R - q*n; d = q;
。
if(i==|A| or R==0) goto 6.;
if(i>=|A|-r) d = q + 1;
4
if(A[i]>=d)
{
R-=d;
A[i]-=d;
}
else
{
R-=A[i];
A[i] = 0;
n = |A|-(i+1);
q = floor(R/n);
d = q;
r = R - q*n;
}
i=i+1; goto 2.;
if(R>0) A[|A|-1] -= R; return A;
非正式解决方案最优性证明:
让n = |A|
。
案例0:n==1 -> C[0] = R
案例1:n>1 && A[i]>=q && A[j]>=q+1 for j>=max(0,n-r)
最佳解决方案由C[i] = q for i<n-r && C[j] = q+1 for i>=n-r
给出。
假设C'[i] = C[i] + E[i]
给出了另一个最优解,其中E
的约束为:E[0]+...+E[m-1]=0
(否则C'
会违反C'[0] + ... + C'[n-1] = R
),{{1} (否则C[i]>=-E[i]
会违反非负面约束),C'[i]
(来自E[i] <= A[i] - C[i]
)和C'[i]<=A[i]
(来自E[i]<=E[j] for i<=j
),然后:
C[i]<=C[j] for A[i]<=A[j] && A[i]<=A[j] for i<=j
最后一个不等式是正确的,因为对于每个术语L_2' - L_2 = 2*q*(E[0]+...+E[n-r-1]) + 2*(q+1)*(E[n-r]+...+E[n-1]) + (E[0]^2 + ... + E[n-1]^2) = 2*q*0 + (E[0]^2 + ... + E[n-1]^2) + 2*(E[n-r] + ... + E[n-1]) >= 0
,如果它至少对2*E[n-i], 1<=i<=r
是负的,则会有相应的术语E[n-i]^2, 1<=i<=r
取消它。让我们分析E[n-i]<-1
,显然2*E[n-i] = -2
不足以在这种情况下取消它的情况。但是,由于E[n-i]^2 = 1
的所有元素总和为E
,因此存在0
:这样j!=n-i
会对其进行补偿,因为我们有E[j]
这个词。对于每个可能的解E[j]^2
,在L_2
&lt; = L_2'
之后的最后一个不等式中,这意味着C'
最小化C
。看到L_2
最小化也得到满足是微不足道的:L_inf
,如果我们有L_inf = q + (r>0) <= L_inf' = max(q+E[0], ... , q+E[n-r-1], q+1+E[n-r], ... , q+1+E[n-1])
,我们得到更高的最大值,我们也可以永远不会减少最大值,因为E[i]>1 for i<n-r, or E[j]>0 for j>=n-r
总和为E
。
案例2:0
在这种情况下,最佳解决方案要求所有n>1 && there exists k: A[k]<q
都C[k] = A[k]
。我们假设存在一个最优解k: A[k]<q
,C'
。存在C'[k]<A[k]<q -> C'[k]<q-1
,i>=k
。假设没有这样的C'[i]<q-1 && C'[i+1]>=q-1
,然后是i
和C'[k] == C[n-1] < q-1
,这是一个矛盾,这意味着这样的C'[0]+...+C'[n-1]<n*q-n<R
确实存在。还存在i
j>k
(如果我们认为这是不真实的,我们再次与C[j]>q && C[j-1]<C[j]
求和C
相矛盾。我们需要这些证据才能满足R
。让我们考虑修改后的解决方案C[t]<=C[l] for t<=l
。 C''[t] = C'[t] for t!=i,j; and C''[i] = C'[i]+1, and C''[j] = C'[j]-1
。最后一个不等式来自L_2' - L_2'' = C'[i]^2 - (C'[i]+1)^2 + C'[j]^2 - (C'[j]-1)^2 = -2*C'[i] + 2*C'[j] - 2 = 2*((C'[j]-C'[i])-1) > 2*(1-1) = 0
。如果我们增加(C'[i]<q-1 && C'[j]>q) -> C'[j] - C'[i] > 1
,我们证明L_2'>L_2''
。通过归纳,最优解应该具有C[i]: C[i]<A[i]<q
。完成此操作后,可以使用简化问题C[l]=A[l] for all l: A[l]<q
归纳地继续进行。
案例3:n' = n-(i+1), R' = R - (C[0]+...+C[i]), q' = floor(R'/n'), r' = R' - q'*n', D[0] = A[i+1], ..., D[n'-1] = A[n-1]
自n>1 && A[i]>=q && A[j]<q+1 for j==max(0,n-r)
以来,这意味着A[k]>=A[i] for k>=i
。但由于我们还A[i]<q+1 for i<=j
这意味着q<=A[i]
,因此我们无法在任何A[i]==q
中添加任何余数。 C[i] : i<=j
的最优性来自案例1中的证明(证明有C[i]=A[i]=q for i<j
项更普遍的证明)。由于问题对于q+1
来说是最佳的,我们可以开始解决减少的问题:0<=i<j
。
案例0,1,2,3都是可能的情况。除了明确给出解决方案的案例0和案例1之外,2和3中的解决方案将问题减少到较小的问题,其再次落入其中一个案例中。由于每个步骤都会减少问题,因此我们可以通过有限的步骤获得最终解决方案。我们也不会多次引用一个元素,这意味着D[0] = A[j],...,D[n-j] = A[n-1]
时间,但我们需要O(n)
进行排序,因此最终我们的算法时间复杂度为O(n*log(n))
。我不确定这个问题是否可以在O(n*log(n))
时间内解决,但我觉得没有排序就无法逃脱,因为案例2和3严重依赖它,所以也许O(n)
是可以实现的最佳复杂性。