工作安排问题

时间:2009-12-19 10:20:01

标签: php pseudocode

我正在开发一个应用程序,我需要在轮换时间表上为成员自动安排作业。我不太擅长解释规则,所以这里有一些数据可以帮助解决:

职位:职称,每周一至周三等规则 类别:一组职位
团体:另一组职位。同一组中的职位不能在同一天分配 成员:在指定日期分配到职位的用户。

对于当月的每个日期,成员被分配到职位(均按升序排列)。如果成员被分配到一个类别中的某个职位,则下一次出现同一类别中的职位时,将按字母顺序(或列表的开头)分配下一个成员,例如。

成员:M1,M2,M3,M4
C1类中的位置:P1,P2,P3
位置P1的成员:M1,M2,M3,M4
位置P2的成员:M1,M2,M3
位置P2的成员:M1,M3,M4

如果为P1分配了M1,如果接下来是P2,则将分配M2。引入了额外的复杂层,如果P3接下来,则M3被分配。系统必须跟踪M2被“跳过”的事实并在下一次分配M2(如果可用),然后分配M4,或者等到它到达M2可用的位置(当有许多'被跳过时,这变得更加复杂'成员)。

如果一名成员表示他将无法在该日期上任,那么该成员也将被跳过。系统需要优先考虑跳过的成员,在它们出现时以某种方式识别它们,然后跳转到列表中的下一个逻辑人员。由于日期冲突,跳过也适用于群组。

我已经有了一个临时[和凌乱]的解决方案,我不再理解,即使我在其中有很多评论解释每一步。它的弱点在于与被跳过的成员打交道。

如果您打算对此进行编码,您会怎么做?我在PHP中实现它,但伪代码也可以。

3 个答案:

答案 0 :(得分:6)

我的解决方案: 您需要一个PriorityQueue(在SplPriorityQueue下可以在PHP中使用)。 PriorityQueue为您提供具有降序优先级的元素(按值排序,最小值 值具有最高优先级。)

每个成员都获得一个指定的值。此值是一个带有n位数的ASCII数字(为方便起见,您可以使用8位数字),在n个位置填充零。之后你追加 名字。您还可以向每个成员添加可用职位

所以(n = 5):

  • M1值:99999Albert P1,P2,P3
  • M2值:99999Susi P1,P2
  • M3值:99999Bob P1,P3

这样可以轻松按优先级和名称对成员进行排序。

的制备:将

阳光灿烂的日子。您正在检索指定的位置和给定日期的类别。每个成员都加载在一个长列表中。没有出现在工作中的每个成员都没有加载,但是他的价值减去了两个。鲍勃不在这里,所以它的新值达到99997Bob。这意味着下次将自动选择Bob。 所有其他成员的价值减去了一个。

映射为特定日期分配的位置(使用SplObjectStorage):

P1-> M1,M2,M3,M4等 P2->等

地图仅包含今天必须分配的位置。

之后

过滤器: 您必须查找组并删除地图上今天无法分配的任何位置。你的小组描述有点不清楚。

分配:

  • 您选择要分配的位置
  • 获取可以填补职位的成员列表
  • 从列表中删除可用成员并将其放入PriorityQueue
  • 从PriorityQueue中通过extract()分配位置(正确分配已完成 automaticially)。分配的每个成员将增加其值 一个(所以如果你在这里工作,减少和增加水平)。 如果你在这里并且由于某种原因没有被分配到一个职位,你得到 小罚一。如果你不在这里,你将被罚两分。
  • 完成后,再将剩余成员放在列表中,清除PQueue和 继续下一个任务。

注意事项:

  • 你必须要小心,总有足够的人担任某个职位。

答案 1 :(得分:1)

UFF。我不跟你描述,但在类似的情况下我用sql来解决这类问题。如果你使用PHP我猜你有可用的SQL。

我建议做的是找到一种方法将这些信息存储到一组表中,然后确定sql查询为您提供所需的答案。通常,在sql中执行它比在过程语言中更简单。

例如,对于跳过的部分,

您可能有一个列,记录上次分配某人的时间,然后按此顺序(以便您选择长时间未分配的人)。或者,您可以按列跳过次数并按此顺序排序。

答案 2 :(得分:0)

据我所知,有'm'成员和'n'职位。

类别:一组职位 - 在该类别中被分配一个职位的成员不能拥有另一职位?

组:一组职位 - 同一组中的职位必须在不同的日期分配。

最后,一个职位有一个可以填补它的成员列表。

从数据结构的角度来看,将成员放在一个链表中 - 每个成员必须有一个额外的[position,day]列表,它们最终被分配。然后,对于每个位置,都有一个可以填充该位置的成员的引用列表。将类别实现为另一个职位的参考列表,以确定其所在的类别。

实际分配:让一天计数器= 0,并迭代这些位置。对于每个位置P,迭代可以填充它的成员。如果出现以下情况,成员M可以填补该职位:

  • 他填写的任何职位P2都不与P分享一个类别。
  • 他在日期= daycounter填充P2的任何位置都不与P共享一个组。

如果他可以填充该位置,则[position,day]对被添加到该成员,并且该成员的节点被移动到列表的END(这就是为什么需要引用的原因 - 所有引用仍然有效即使节点移动了)。这确保了'跳过的'成员被赋予最高优先级,而未被到达的成员被赋予次优先级。

填补职位后,转到下一个职位。如果该位置共享一个已经分配了位置的组,则跳过它,遍历所有位置,直到您可以在第1天分配尽可能多的位置。然后,增加日期计数器并重复第2天。这应该给你所有工作的最大分配(不确定最大值)。

提示:当一个成员移动到成员列表的末尾时,为了防止必须遍历列表,保持对结尾的引用 - 对于下一个位置,你需要从头开始,所以没有指出整个过程。