用于最佳地选择执行任务的动作的算法

时间:2010-06-06 14:57:18

标签: algorithm optimization math computer-science

有两种数据类型:任务和操作。一个动作需要花费一定的时间来完成,这个动作包含一组任务。任务有一系列操作,我们的工作是选择其中一个。所以:

class Task { Set<Action> choices; }
class Action { float time; Set<Task> dependencies; }

例如,主要任务可能是“获得房屋”。这项任务可能采取的行动:“买房子”或“盖房子”。 “建造房屋”的行动需要10个小时,并且具有依赖性“获取砖块”(可能需要6个小时)和“获取水泥”(花费9个小时)等等。

总时间是执行所需操作的所有时间的总和(在这种情况下为10 + 6 + 9小时)。我们希望选择总时间最短的行动。

请注意,依赖项可以是菱形的。例如,“获取砖块”可能需要“获取汽车”(运输砖块)和“获取水泥”也需要汽车。即使你做“获得砖块”和“获得水泥”,你只需要计算一次一次所需的时间。

另请注意,依赖项可以是循环的。例如“Money” - &gt; “工作” - &gt; “汽车” - &gt; “钱”。这对我们来说没问题,我们只选择所有的“钱”,“工作”和“汽车”。总时间只是这3件事的时间总和。

数学描述:

actions成为所选择的行动。

valid(task) = ∃action ∈ task.choices. (action ∈ actions ∧ ∀tasks ∈ action.dependencies. valid(task))
time = sum {action.time | action ∈ actions}
minimize time subject to valid(primaryTask)

我对最佳解决方案感兴趣,但也对近似解决方案感兴趣。也许某种动态编程可以帮到那里?如果问题是树形结构,那么动态编程可以在多项式时间内给出最优解,但是钻石结构似乎使问题更加困难。如果你有一个算法,但是如果有循环则不起作用,请发布它!我可能仍然可以从中学到很多东西。

alt text

方框表示任务,圆圈表示操作(执行操作的时间在圆圈中)。如果该任务是该操作的依赖项,则该操作对任务具有一行。以下是关于图片的问题描述:如果选择了矩形(=任务),则必须选择其中一个圆(=动作)。如果选择了一个圆,则必须选择连接矩形的所有。目标是最小化所选圈子中的数字总和。

在这种情况下,最佳解决方案是在顶部任务中选择时间2的操作,在底部任务中选择时间1的操作。总时间为2 + 1 + 1 = 4。在这种情况下,有2个最佳解决方案。第二种解决方案是在顶部任务中选择时间为3的操作,在右下角任务中选择时间为1的操作。总时间再次为3 + 1 = 4。如果我们在顶部任务中选择时间3的操作,则不必执行左下角任务,因为时间3和左下角任务之间没有行。

我为糟糕的绘图道歉;)还有两个例子(每个例子的最佳解决方案用蓝色表示,主要任务用灰色表示): alt text

6 个答案:

答案 0 :(得分:4)

您可以将其建模为图表,并使用shortest path algorithm查找解决方案。每个任务都是一个节点,而动作将是图中的边缘。

事实上,将节点表示为状态和边缘可能更容易,因为边缘在状态之间转换所需的操作。

如果您将任务简单地视为操作的集合,并将节点建模为状态,将操作建模为这些操作之间的过渡。而不是将“获得房子”作为主要任务,将“开始”和“拥有房屋”视为2个节点,并将“获得房屋”视为它们之间的过渡。可以将“获得房屋”转换动作分解成表示中间状态和动作(即节点和边缘)的图形。您应该能够根据需要将问题分解,并从结果图中计算出最短路径。

答案 1 :(得分:1)

我想我早在PERT图表的背景下做过这个。

这些网络有多大,您需要多久解决一次?在看到之前,您实际上没有性能问题。

我会使用动态编程。在我从经验中发现它们之前,我不会认为共享子任务会成为问题。

答案 2 :(得分:1)

您可能正在寻找偏序计划算法:http://blackcat.brynmawr.edu/~dkumar/UGAI/planning.html#algorithms

答案 3 :(得分:1)

存在过于挑剔的风险,这似乎是典型的关键路径方法(CPM)问题,而不是PERT。 PERT假定每项任务的最差,最佳和平均完成时间,而Jules仅为每项任务指定了一次。也就是说,您可以使用线性编程来查找关键路径,并为每个活动生成最早的开始时间,最新完成时间等。 Here's该方法的有用的一页描述。

答案 4 :(得分:0)

答案 5 :(得分:0)

我相信每个可能的执行路径必须以一个任务结束,其中一组选项完全由没有依赖关系的Actions组成。

如果确实如此,那么您可以轻松确定每个此类任务的最短时间。

然后向后工作只依赖于你已“解决”的任务的动作,并计算它们的总时间。

在所有可能的路径中向后工作,直到开始。

运行时间应该是O(图中的节点数),这应该与生成图表所用的运行时间相同。