分配工作人员任务

时间:2013-09-05 11:06:47

标签: javascript algorithm artificial-intelligence

在模拟中,工作人员必须在地图上移动执行任务。

每个模拟'tick',它们可以移动一个方格。

一旦它们与它相邻,执行任务需要10个滴答。

无法传递任务方块。与工人在一起的广场不能通过。不止一个工人可以在广场上工作。

工人不互相竞争;目标是尽快完成所有任务。

添加:理想情况下,算法应该直观易懂,易于实现。这不是每个人都想要的吗?如果它有效,它是一个很大的优点模型可以更新和重用,而不是经常从头开始重新计算。理想情况下,它可以使用当地最优,所以它不会试图暴力破坏NP问题,但避免过于贪婪并提前思考,而不是基本上随意的游荡,工人们很少注意别人的计划。 / p>

以下是一个例子:

enter image description here

工人1和2必须完成方块A,B,C和D上的任务。

您如何确定哪个工作人员执行哪项任务?

似乎不言而喻,1应该做A,2应该做C。

1与A相距4个方格,因此将在14个刻度中完成。 1应该去哪里,为什么?

如果有另一项任务 - E - 直接放在B上面怎么办?

工人用来决定接下来要去哪里的逻辑是什么?

我尝试了什么:

这是一个业余爱好的RTS游戏,我已经尝试过这样做,以便闲置的工作人员前往最近的任务,或者继续执行其他工作人员没有做的最近的任务。

这种贪婪的方法被证明是非常低效的,而且玩家测试清楚地表明它是站不住脚的。因为战略采矿/建筑/农业是游戏的关键,并且因为我不希望玩家微观管理和路由所有工人,所以我正在寻找一种相当公平且合理的最佳算法,工人可以使用它。

8 个答案:

答案 0 :(得分:11)

即使有一个工人,这也是NP完全优化问题(然后它成为旅行商问题)所以让我们忘记“最优”。

如果你知道工人1将处理任务A1,A2,......,工人2将处理任务B1,B2,......等等,那么你可以在做出决定之后尝试解决独立的旅行推销员问题一个接一个,你得到了所有工人的时间表和路径。

然而,问题是你无法知道在解决该套装的旅行商问题之前为工人完成一组任务A1,A2,...需要多长时间,因为步行时间会影响到完成任务的总时间。

因为它只是一个游戏,并且工人可以被认为不是最佳思想家,我会使用随机过程:

  1. 随机将所有任务分配给所有工作人员
  2. 使用贪婪算法计算工作人员任务组中每个工作人员的步行时间上限
  3. 尝试随机移动,将一个任务从一个工作人员移动到另一个工作人员,或者在两个工作人员之间交换任务
  4. 根据禁忌搜索或模拟退火原则接受该移动,具体取决于移动是否减少最大执行时间(行走时间+任务执行时间)的上限,因此目标是让最后一个任务完成为尽可能早地
  5. 在N次迭代之后,停止并计算旅行商问题的更好解决方案,例如使用随机搜索,或明确问题是否很小(例如,每个工人少于10个任务)

答案 1 :(得分:7)

不要贪婪地将工作人员分配到最近的任务,而是贪婪地将最远的任务分配给其“最近的”工作人员 - 也就是说,路径紧密通过且有足够的松弛时间来处理它的工人。这样你就有了一个(贪婪的)概念,即完成所有任务所需的最短时间。

例如:

D是“最遥远的任务”,即使没有定义该术语,所以将D指定为1.它是15 + 10个单位,所以设置t = 25,松弛在2到25。

现在这里是分配下一个任务的距离成本,考虑到最短的路线。

    A   B   C   D  
1  10  22  24   -
2  29  19  18   -

但根据贪婪的想法,这是真正的成本;增加到最长时间t

    A   B   C   D  
1  10  22  24   -
2   4  0    0   -

由于C成本最高(从贪婪的角度来看,这是最危险的任务), 将C指定为2。

接下来的费用如下

    A   B   slack    A  B
1  10  22     0     10 22
2  21  11  (-)7     14  4

分配B因为22是最大时间t的最大增量。将其分配给工人2。

...

背包问题有很多方法,但如果需要简单,这可能是下一个尝试的方法。也许存储任务之间的最短路径。这是一种过于贪婪的方式,可以提前思考一下!

答案 2 :(得分:5)

这确实听起来很像(已经提到的)多个座席的旅行商问题(TSP,http://en.wikipedia.org/wiki/Travelling_salesman_problem)。这实际上是类似于多背包(MKP,http://en.wikipedia.org/wiki/Knapsack_problem#Multiple_knapsack_problem)或甚至Bin包装(http://en.wikipedia.org/wiki/Bin_packing_problem)的问题。

有一组算法可能适用于这种情况,它被称为“蚁群优化”(ACO,http://en.wikipedia.org/wiki/Ant_colony_optimization_algorithms)。

要结合这两者,有些实施使用ACO来解决MKP问题;在这种情况下,这似乎是一种很好的方法,例如:

http://www.researchgate.net/publication/221246039_Probabilistic_Model_of_Ant_Colony_Optimization_for_Multiple_Knapsack_Problem

答案 3 :(得分:3)

因为它是一个RTS游戏,我会尝试选择一种简单,快速,易于理解的方法。

  1. 必须因为性能很重要
  2. 必须易于理解为什么工人会到处去,因为在游戏中你想让仆从按照预期行事。不要试图为球员思考。
  3. 首先,当然,我会尝试贪婪的方法。但是你已经提到它只是不起作用。

    接下来我会尝试类似二阶贪婪算法的东西。每个工作人员选择最接近的任务A,然后选择A旁边最接近的任务B.他们尝试(!)选择目前为止没人选择的任务。这样的事情。

    保持小巧简单。请注意:无论您选择何种算法,都会成为悲惨失败的案例。毕竟有no free lunch

答案 4 :(得分:3)

我会建议类似于TobiMcNamobi的方法,但更精确:

  • 为每个工作人员初始化一个空的工作队列,并完成此队列所需的时间z
  • 为每个任务提供一个属性d,设置为0.它表示根据当前计划,此任务“已经处理了多少”。
  • 重复所有工作人员至少有一份工作z>某个固定值已经过了一段时间):
    • 使用最小w的其中一名工作人员z
      • p设置为w队列中最新条目的位置或w的位置 队列是空的。
      • 按距离p的顺序遍历不在此工作队列中的任务
        • 计算distance/d
        • 如果您找到此值的最小值,请将此任务添加到工作人员的队列,将任务距离+ 7添加到z并将1/z添加到d。打破循环。

在运行此操作之前,您应该根据距离最近的任务的距离对工作人员进行排序。否则,第一个任务是相当随机的,第一个任务是最重要的任务。

每当添加作业或工作人员时,您都可以更新此项。重用一些以前的值(可能存储中间结果,比如将匹配的z添加到工作队列中的任务中),此更新应该相当快。

这也可能需要偶尔更新一次,因为一旦你走得太远,这个算法会变得非常不准确。

distance/d公式可能还需要一些调整,但我想测试会对此有所帮助。

“最小”的定义取决于您。我建议你拿一个当地的最低限度,也许最多可以再检查5个任务。找到全球最小值似乎不必要的昂贵。

答案 5 :(得分:3)

我猜测“实时”的贪婪原因是糟糕的,因为工作人员最终会对他们到达时完成或接近完成的任务进行疯狂追逐。因此,我将提出一种计划算法:一种智能地将每个工作者分配给一系列任务的方法,其中序列的并集是一个封面。

正如其他人所说,TSP已嵌入此规划要求中,因此这是NP难题。

但是TSP有一个简单的多项式时间近似算法,它产生的路径长度不超过2倍。只计算一个最小生成树,包括所有工作站点和一个工作人员。然后,在每个方向上遍历每个边缘一次的明显路径接触每个节点。

当然,当回溯时,你可以通过已经访问过的节点“蜂鸣”。这意味着只需通过预先遍历MST来发出任务序列。由于三角不等式,这条路径通常比2x最优更好。 (我假设这里允许对角线步骤。否则这不是真的,但算法仍能正常工作。)

所以规划的方法是:

  1. 为每个工作人员和所有工作地点计算MST。
  2. 使用与每个工作人员W关联的MST来计算预订路径:S_W,T_Wi,i = 1,2 ....这里,S_W是工人W的起始位置,T_Wi是任务位置。 W将会访问他们。
  3. 现在进行简单的事件驱动模拟,以构建如下的计划。 (这是游戏模拟中的“内部”模拟,只是为了制定计划。)
  4. 在下面的算法中,事件包括投射的时钟发生时间,并以此时间作为关键字放置在事件队列中。

    Let Arrive(W, T, L) be an arrival event of worker W 
      at task T starting from previous location L, traveling the shortest path
    Let Complete(W, T) be a completion event for worker W of task T
    
    For each worker W, place Arrive(W, T_W1, S_W) on the queue
    While events are left on the queue
      Remove an event E
      If E is an arrival Arrive(W, TW_i, L) 
        If TW_i has no worker yet, 
          Assign TW_i to W
          Schedule a future event Complete(W, TW_i) 10 time units in the future.
        Else // T has a worker
          Schedule Arrive(W, TW_{i+1}, L), if TW_{i+1} exists
      Else E is a completion Complete(W, TW_i)
        Schedule Arrive(W, TW_{i+1}, TW_i), if TW_{i+1} exists
    

    现在按照在此(内部)模拟中发现的顺序执行每个工作人员的分配。

    使用先前的位置和目的地计算到达时间以获得最直接的路线。

    这个算法相当贪婪,但它“提前”贪婪。因为你正在模拟提前分配任务,所以你永远不会将一个疯狂的追逐工作者发送给另一个工人到达之前完成或完成的任务。

    此外,没有工人可以覆盖的距离超过最佳TSP路线的2倍。

答案 6 :(得分:2)

(注意:完成所有这些后我意识到你说了14个滴答声因为“邻近”你正在考虑“在...之上”,而我把它解释为“旁边”...所以请记住我的计算是基于那,但它不应该改变结果。)

我的第一直觉是首先根据最佳完成时间为每个工人建立一个独立队列,假设没有其他工人存在并稍后处理冲突(请注意,根据我的解释,当1完成A时,然后B比D更接近,但我们要防止的关键是1取B):

1 [A, B, C, D]
2 [C, B, A, D]

然后我会计算每一个的移动+工作时间:

1 [A=3+10, B=8+10, C=1+10, D=20+10]
2 [C=7+10, B=1+10, A=10+10, D=11+10]

作为参考,这里只是总滴答:

1 [A=13, B=18, C=11, D=30]
2 [C=17, B=11, A=20, D=21]

这是累积的:

1 [A=13, B=31, C=42, D=72]
2 [C=17, B=28, A=48, D=69]

那么如果您只是遍历每个任务以查看谁拥有最低时间并将其从其他工作人员的队列中删除,会发生什么?显然,一旦你改变了一些东西,所有的累积时间都必须重新计算(我将手动做,唉)

开始(与上面相同):

1 [A=13, B=31, C=42, D=72]
2 [C=17, B=28, A=48, D=69]

1具有最低的A时间,因此2失去它,并且2的D时间被重新计算:

1 [A=13, B=31, C=42, D=72]
2 [C=17, B=28, D=59]

2胜B,所以C和D再次改变1次:

1 [A=13, C=32, D=62]
2 [C=17, B=28, D=59]

2胜C,再次改变1的D时间:

1 [A=13, D=24]
2 [C=17, B=28, D=59]

1胜D:

1 [A=13, D=24]
2 [C=17, B=28]

如果B上方还有另一个任务E怎么办?对不起,我没时间计算这个。

答案 7 :(得分:1)

我认为工人的外表需要与人类所做的相似(算法需要将每件作品分配为人类的力量)。如果算法没有,玩家会想知道AI是什么 做和可能尝试手动路由(即使它不是最佳)。我认为任何“全局最优”解决方案可能都不会像人类那样做......

所以,我认为你的(威尔)初始算法可能只需要稍微改进即可。让每个工作人员前往最近的疫苗接种工作,但模拟它去那里并在工人到达工作时停止模拟或另一个工人离得更近(那个工人将抓住那份工作)。如果没有达到疫苗接种工作,请选择最近的工作并在那里帮忙。