假设您有
T
(< = 20)个任务。每项任务都需要相应的时间才能完成。完成后 每个任务,您都可以获得可用于指定任务的工具 完成它们s
:( 0 <= s <= 15)次更快 - 如果任务先前需要时间t_i, 现在需要时间ceil(t_i / s)
。它需要的最短时间是多少 完成所有任务?请注意,每项任务一次只能使用一个工具 - 您无法在任务中间切换工具,也无法同时使用多个工具。
例如,假设您必须完成3项任务。
任务#1需要5分钟。完成后,您将获得一个可以的工具 完成任务#2快三倍,任务#3快两倍。
任务#2需要10分钟。完成后,您将获得一个可以的工具 完成任务#1快两倍,任务#3快五倍。
任务#3需要5分钟。完成后,您将获得一个可以的工具 完成任务#1快两倍,任务#2快两倍。
在此示例中,最快的方法是首先完成任务#1,使用任务#1中的工具在ceil(10/3)分钟内完成任务#2,然后使用任务#2中的工具完成任务#3 in ceil(5/5)分钟。这导致总共5 + 4 + 1 = 10分钟。
我想到这样做的一种方式是递归)。所花费的总时间是:
ceil(curTask/bestTool) + min({otherTasks})
其他任务是尚未完成的任务。在此过程中,您将为每项任务更新最佳工具。
然而,这种天真的蛮力显然需要太长时间。我试着将其转换为memoized递归(DP - 动态编程)但我不确定要缓存哪些值。
另一种可行的方法是创建某种图形并运行像dijkstra这样的最短路径算法,但我认为仅创建图形本身就会有太大的复杂性。
解决此问题的最佳方法是什么?
答案 0 :(得分:1)
动态编程,按累计时间记忆,剩余任务和每项任务的时间乘数。
一些示例Python代码(如果在每个任务之后丢弃工具):
from math import ceil
taskTimes = {1:5, 2:10, 3:5}
tools = {1:(1,3,2), 2:(2,1,5), 3:(2,2,1)}
cache= {}
def rec(totalTime, tasksLeft, multipliers):
if len(tasksLeft) == 0:
return totalTime
key = (totalTime, tasksLeft, multipliers)
if key in cache: return cache[key]
t = 10**10
for task in tasksLeft:
newTasksLeft = tuple(i for i in tasksLeft if i!=task)
curTime = ceil(taskTimes[task] / float(multipliers[task-1]))
t = min(t, rec(totalTime+curTime, newTasksLeft, tools[task]))
cache[key] = int(t)
return cache[key]
print rec(0, tuple(range(1,len(tools)+1)), tuple([1]*len(tools)))'
如果随着时间的推移保留最好的工具:
from math import ceil
taskTimes = {1:5, 2:10, 3:5}
tools = {1:(1,3,2), 2:(2,1,5), 3:(2,2,1)}
cache= {}
def rec(totalTime, tasksLeft, multipliers):
if len(tasksLeft) == 0:
return totalTime
key = (totalTime, tasksLeft, multipliers)
if key in cache: return cache[key]
t = 10**10
for task in tasksLeft:
newTasksLeft = tuple(i for i in tasksLeft if i!=task)
newMultipliers = tuple(max(a,b) for a,b in zip(tools[task], multipliers))
curTime = ceil(taskTimes[task] / float(multipliers[task-1]))
t = min(t, rec(totalTime+curTime, newTasksLeft, newMultipliers))
cache[key] = int(t)
return cache[key]
print rec(0,tuple(range(1,len(tools)+1)),tuple([1]*len(tools)))