找到完成可以按任何顺序完成的操作的最短时间

时间:2014-11-01 03:16:56

标签: algorithm recursion dynamic-programming graph-algorithm

  

假设您有T(&lt; = 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这样的最短路径算法,但我认为仅创建图形本身就会有太大的复杂性。

解决此问题的最佳方法是什么?

1 个答案:

答案 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)))