找到从A机器中获取C礼品所需的最短时间?

时间:2014-10-09 06:11:21

标签: algorithm math logic computational-geometry

我接受了下周的采访,并且正在为此练习问题。我遇到了这个问题,你能帮我解决一下吗?

  

礼品自动售货机,你有 B pouches   收集礼品。每个礼品自动售货机都有无限的礼品。

     

每台机器在 Si 秒时开始丢弃礼物并保持   每隔 Ii 秒丢一份礼物。 你可以安排小袋   你喜欢的任何方式,但一旦他们被设置在一台机器下面,你就不能   把它移到另一台机器上。你需要收集最少的C礼物   在最短的时间内。

     

输入

     

第一行包含整数A,B,C。

     

第二行包含整数, Si 。 (用空格分隔),   我从1到A。

     

第三行包含整数 Ii (用空格分隔),I   从1到A。

     

输出

     

一个给出最小计算时间的整数。

我认为这种方法效率很低。我认为我们可以让所有子集的基数等于B,然后选择给出最小时间的子集。

这种方法似乎是暴力,所以我正在寻找另一种替代方法。

你们中的任何人可以帮我吗?

4 个答案:

答案 0 :(得分:1)

首先编写一个函数

int max_num_gifts(A,B,t,S[],l[])

计算t时间内您可以使用B包收集的最大礼品数量。这可以在O(A)时间内完成:给定S[]l[],机器A[i]丢弃的礼物数量为(t-S[i])/l[i]+1。然后获得丢失最多礼物的顶级B机器。有关如何在O(n)时间内进行选择,请参阅How to find the kth largest element in an unsorted array of length n in O(n)?

然后,您可以循环遍历时间t=1,2,...直到max_num_gifts >= C。或者更好的是,您可以使用二进制搜索来查找t:从t=1开始,然后检查t=2t=4t=8等,直到您得到一个太大的数字,然后二进制搜索所需的t

整体时间复杂度应为O(A* lg(T_min))

答案 1 :(得分:0)

一种可能的方法如下:

通过逐步完成事件来同时模拟每台自动售货机。对于每台机器计算它将丢弃礼物并逐步完成该时间的时间。

此外,维护所有机器的优先级队列,按照到目前为止的礼品数量排序。

然后,如果礼品总数B机器等于C,那么这是最短时间T_min

Order of complexity: O( T_min * A * logA )

答案 2 :(得分:0)

首先,您必须按S_i按升序对自动售货机的起始时间A进行排序。我认为,有了这个先决条件,如果你把问题写成一个等式,问题会变得更清楚:

Problem as euqation

其中\ThetaHeaviside step function,而特殊括号表示floor function

T超过gamma时查找C的小型python脚本可能看起来像

import numpy as np

A=10
B=3
C=10
S=np.sort(np.random.randint(100, size=A))
gamma=0
t=1

while gamma<C:
    for i in range(1, B):
        gamma=(1 if t-S[i] > 0 else 0) * np.floor(t/2)
        t = t+1

print "minimal t: %d" % t

我没有从文件中读取输入值ABC,并在0到100之间随机生成起始时间S。您还需要检查是否B<A

答案 3 :(得分:0)

为简单起见,让我们做出以下假设(我们可以稍后放松这些假设并解决边缘情况):

  1. 每台机器都会产生一个“分数”的礼物&#39;每次都是1 / l [i]。
  2. 所有S [i]都不同,即没有两台机器同时开始分配。
  3. 让我们先考虑两个边界案例:

    • 如果我们有比机器更多的袋子,我们不必在它们之间做出选择;在每次踏步S [i]时,我们都会给机器i添加一个小袋,并继续收集所有礼物,直到我们总共有C。
    • 如果| B | = 1(只有一个小袋),我们在最小的S [i]添加小袋。我们一直踩着时间,直到我们到达C,或者直到另一台机器在那时导致更高的总数,然后由于20-20事后才切换袋。注意,在数学上,切换点是在S [i]处穿过x轴的两条线交点,并且具有斜率1 / l [i]。我们稍后会再回过头来看。

    以上考虑导致以下一般(天真)算法,伪代码。

    def min_time_to_reach_c(S,l):
        def function yield(m, t) = max(0, t-S[m])/l[m]
    
        Active = {} # The currently best set of machines that we attach our pouches to
        Inactive = {1,..,A} # The other machines
        t = 0 # time step
        sum = 0 # total gifts collected so far
        gift_rate = 0 # gifts we receive at every time step
    
        while sum < C:
           if |Active| < B and t == S[m’] for some m’ in InActive:
              # we have not used up all our pouches yet
              Active += {m’}
              InActive -= {m’}
              gift_rate += l[m’]
           else if yield(m’,t) > yield(m,t) for some m’ in InActive, m in Active: (*)
             # for all successive time steps, m’ will be preferable to m
             Active   += {m’} - {m}
             InActive -= {m’}
             sum += yield(m’,t) - yield(m,t)
             gift_rate += l[m’] - l[m]
           sum += gift_rate
           t += 1
       return t
    

    这种幼稚算法的复杂性至多为O(t_min * A),如果在每个步骤(*)中我们确定了交叉&#39;通过每个线性通道找到(In)有效集的最大(最小)产量。

    如果A&lt; t_min,我们实际上可以通过考虑几何体来做得更好 - 它可以被视为sweep line algorithm。事实上,没有必要访问每个时间点,我们只需要看看有趣的&#39;机器启动或交叉的点。在预处理步骤中,我们计算所有具有交叉点的时间步长(如果一条线不与另一条线交叉并且被支配,则可以立即丢弃)。在每个这样的点上,我们可以如上所述更新我们的有效集和收益率。我们还计算当前速率达到C的距离;如果这发生在下一个S [i]或过境之前,我们就完成了。

    扫描线算法的复杂性是预处理步骤的O(A ^ 2),以及最多2A更新步骤的另一个O(A ^ 2)(或者更好,如果我们使用O(A log A)一个优先级队列,用于跟踪行的相对顺序)。请注意,这与t_min无关。

    我认为一个有趣的后续问题是:如果你事先不知道S [i]和l [i],最好的策略是什么?