我接受了下周的采访,并且正在为此练习问题。我遇到了这个问题,你能帮我解决一下吗?
礼品自动售货机,你有 B pouches 收集礼品。每个礼品自动售货机都有无限的礼品。
每台机器在 Si 秒时开始丢弃礼物并保持 每隔 Ii 秒丢一份礼物。 你可以安排小袋 你喜欢的任何方式,但一旦他们被设置在一台机器下面,你就不能 把它移到另一台机器上。你需要收集最少的C礼物 在最短的时间内。
输入
第一行包含整数A,B,C。
第二行包含整数, Si 。 (用空格分隔), 我从1到A。
第三行包含整数 Ii (用空格分隔),I 从1到A。
输出
一个给出最小计算时间的整数。
我认为这种方法效率很低。我认为我们可以让所有子集的基数等于B,然后选择给出最小时间的子集。
这种方法似乎是暴力,所以我正在寻找另一种替代方法。
你们中的任何人可以帮我吗?
答案 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=2
,t=4
,t=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
进行排序。我认为,有了这个先决条件,如果你把问题写成一个等式,问题会变得更清楚:
其中\Theta
是Heaviside 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
我没有从文件中读取输入值A
,B
和C
,并在0到100之间随机生成起始时间S
。您还需要检查是否B<A
。
答案 3 :(得分:0)
为简单起见,让我们做出以下假设(我们可以稍后放松这些假设并解决边缘情况):
让我们先考虑两个边界案例:
以上考虑导致以下一般(天真)算法,伪代码。
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],最好的策略是什么?