【问题标题】:Weighted average distribution algorithm加权平均分布算法
【发布时间】:2015-02-25 16:51:43
【问题描述】:

我有 N 个桶,每个桶的标准化权重为 Wi。我想按重量将 $x 分配给每个桶。每个桶都有算法需要的最小 $ (MINi) 和最大 $ (MAXi)实现。每个桶的最小值和最大值优先于权重。这个问题是否可以在多项式时间内解决?算法是什么样的?

例子:

4 个桶,A、B、C、D

A:WA = 100,MINA = 0,MAXA = 150

B:WB = 100,MINB = 0,MAXB = 60

C:WC = 1,MINC = 20,MAXC = 150

D:WD = 1,MIND = 30,MAXD = 150

总美元 = 150 美元

预期结果:

答:50 美元

乙:50 美元

C:20 美元

价格:30 美元

请注意,C 和 D 使用他们的分钟数,其余的美元平分,因为 A 和 B 的重量相同。

【问题讨论】:

  • “最小值和最大值优先于权重”是什么意思?我们可以有剩余的钱吗?如果桶 A 的最大值为 25 美元,您是否希望桶 A 和 B 中只有 25 美元,因为它们的权重相等,还是我们继续向 B 加钱?
  • 不允许吃剩菜。最大值和最小值仅适用于单个存储桶。因此,如果 A 最高达到 25 美元,B 仍然可以走高,因为它没有达到最高。如果在广告组级别未达到上限,则应应用权重。
  • @collapsar 你不妨把它变成一个答案。
  • 你已经正确地证明了我漂亮的算法是错误的......答案撤回了;-)。但是,我仍然认为多项式时间内的解决方案是可能的。将问题改写为线性规划问题。
  • 暂时撤回另一项声明......抱歉,我认为这不够彻底。

标签: algorithm optimization distribution


【解决方案1】:

令 z 为实参数。我对这个问题的理解是你想找到 z 这样,当桶 i 被分配 max(MINi, min(MAXi, Wi z)),分配的总和等于 x。

这是一个 O(n log n) 时间算法(可能有一个线性时间算法,但如果它确实存在,它可能会更复杂)。直观地说,它的作用是不断增加 z,直到分配的总和等于 x。

z中和的导数是每个桶的导数之和。桶 i 的导数为 0 为 z i 为 a i / W i 是第一个临界点,b = MAXi / Wi 是第二个临界点。我们对这些临界点进行排序,然后追踪得到的分段线性函数。在 Python 3 中(有意避免一些 Python 习语):

import collections

Bucket = collections.namedtuple('Bucket', ('weight', 'min', 'max'))
Event = collections.namedtuple('Event', ('key', 'i', 'derivative'))


def allocate(total, buckets):
  n = len(buckets)
  events = []
  derivative = 0
  residual = total
  derivatives = []
  for i in range(n):
    bucket = buckets[i]
    events.extend([Event(bucket.min / bucket.weight, i, bucket.weight),
                   Event(bucket.max / bucket.weight, i, 0)])
    residual -= bucket.min
    derivatives.append(0)
  events.sort()
  z = 0
  for event in events:
    if derivative > 0:
      w = z + residual / derivative
      if w <= event.key:
        z = w
        break
    residual -= derivative * (event.key - z)
    derivative -= derivatives[event.i]
    derivatives[event.i] = event.derivative
    derivative += derivatives[event.i]
    z = event.key
  allocations = []
  for i in range(n):
    bucket = buckets[i]
    allocations.append(max(bucket.min,
                           min(bucket.max,
                               bucket.weight * z)))
  return allocations

print(allocate(150,
               [Bucket(100, 0, 150),
                Bucket(100, 0, 60),
                Bucket(1, 20, 150),
                Bucket(1, 30, 150)]))
# [50.0, 50.0, 20, 30]
print(allocate(100,
               [Bucket(40, 42, 55),
                Bucket(40, 0, 100),
                Bucket(20, 0, 4)]))
# [48.0, 48.0, 4]

【讨论】:

  • 在算法上面看你的解释。什么是“a”和“b”?
  • @eymlo "其中 a = MINi / Wi 是第一个临界点,b = MAXi / Wi 是第二个临界点"
【解决方案2】:

第 1 步:分配所有最低预算

in your example: 
( 0, 0, 20 ,30)

第 2 步:如果没有边界,则计算理想分配:

in your example: 
(100/202)*150 =74
(100/202)*150 =74
(1/202)*150 = 0.74
(1/202)*150 = 0.74

第 3 步:从理想中减去“当前分配”:

in your example:
0 - 74 = -74
0 - 74 = -74
20 - 0.74 = 19.26
30 - 0.74 = 29.26

第 4 步:将美元/美分分配给第 3 步中的最低值

in your example:
-74 is the lowest value
so just assign a dollar to the first one with the lowest value

第 5 步:重复第 3 步和第 4 步,停止将预算分配给达到上限的存储桶。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 2010-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多