【问题标题】:Scheduling Algorithm for Maintining Two Dimensional Constraint维护二维约束的调度算法
【发布时间】:2010-10-15 00:00:10
【问题描述】:

我的任务是在我的公司执行一个日程安排程序。基本上给定 N 名员工,您应该安排他们在本月轮班。我试图通过蛮力和有序的约束优先级来做到这一点。但是,我在尝试保持垂直和水平约束时遇到了问题。

纵向限制,每个人每个月都应该有相同的班次。 (例如,他们应该在白班、夜班、休息日、早班的平均数量之内)但是,也有一天的横向限制,即每天的班次数量应该每天相等。

我尝试在互联网上搜索,我通常会阅读有关使用遗传算法的答案。在我对遗传算法的研究中,该算法似乎不太适合我的情况。有人知道如何解决这个问题吗?

基于 Enigmativity 评论的附加插图: 基本上有4个班次,

Y 是每月的员工轮班总数,需要平均分配给每个员工。 (即每个员工在当月的班次类型应该相等(或相差一个)) - 垂直约束。

X 是所有员工的每日总数,基本上每个班次也应该平均分配到平日和周末。 - 水平约束

此外,还有其他限制,例如所需班次和相邻班次。但我现在试着用这些平分规则来简化它。

--------------------------------------------------------------------------------
| Employee | 1  | 2  | 3  | 4  | + + + | 28 | 29 | 30 | 31 | S1 | S2 | S3 | S4 |
--------------------------------------------------------------------------------
| EmpA     | S3 | S4 | S1 | S2 | + + + | S3 | S4 | S1 | S2 | Y  | Y  | Y  | Y  |
--------------------------------------------------------------------------------
| EmpB     | S1 | S3 | S4 | S1 | + + + | S2 | S3 | S4 | S1 | Y  | Y  | Y  | Y  |
--------------------------------------------------------------------------------
| EmpC     | S2 | S1 | S3 | S4 | + + + | S1 | S2 | S3 | S4 | Y  | Y  | Y  | Y  |
--------------------------------------------------------------------------------
| EmpD     | S2 | S2 | S2 | S3 | + + + | S4 | S1 | S2 | S3 | Y  | Y  | Y  | Y  |
--------------------------------------------------------------------------------
| S1       | X  | X  | X  | X  | + + + | X  | X  | X  | X  |    |    |    |    |
--------------------------------------------------------------------------------
| S2       | X  | X  | X  | X  | + + + | X  | X  | X  | X  |    |    |    |    |
-------------------------------------------------------------------------------
| S3       | X  | X  | X  | X  | + + + | X  | X  | X  | X  |    |    |    |    |
--------------------------------------------------------------------------------
| S4       | X  | X  | X  | X  | + + + | X  | X  | X  | X  |    |    |    |    |
--------------------------------------------------------------------------------

【问题讨论】:

  • 我不明白你的水平限制。 “每天的班次应该每天相等”是什么意思?此外,您还必须有进一步的限制,例如首选工作日、可用性限制等,否则您的公司只会创建一个固定的时间表——三个白班、三个夜班、三个休息日、三个早班——并将员工分成四组团队。那么,他们不这样做的原因是什么?此外,遗传算法将为每位员工提供每天随机轮班变化的数量 - 这听起来不正确。请提供更多信息。

标签: algorithm scheduling


【解决方案1】:

我目前正在处理一个听起来与您非常相似的护士调度问题。目标是每天为每位护士安排一个轮班(或休息日),以便他们都工作正确的轮班次数(每周工作 40 小时)并满足每天的基线轮班要求(周一 3 名护士、周二 2 名护士等)。 )。这是一个众所周知的问题,并且与任何其他调度问题一样,它是 NP-Hard。

我同意您的评论,即遗传算法不太适合这项任务(或任何 imo 任务)。有更好的方法来解决这个问题,它们已经在约束规划和运筹学领域得到了研究和充分的证明。

我的建议是使用数学编程语言对问题进行建模,并将其编码为约束规划问题或混合整数线性规划 (MILP)。有许多语言可以让您对这些问题进行高级编码,最著名的一种可能是 AMPL。您可以搜索该语言的护士调度示例,这可能会有很大帮助。 AMPL 语言可以很容易地编译成 MILP,然后可以将其传递给像 GLPK 或 CPLEX 这样的求解器。此外,如果您在学术界或有相当可观的预算来解决这个问题,您应该考虑获取 IBM 的 ILOG CPLEX 包并用他们支持的优化编程语言 (OPL) 对您的问题进行编码。这是我正在使用的语言/求解器,我对此非常满意。

请记住,从计算的角度来看,这是非常困难的问题,我会确保您在对项目进行任何成本估算之前熟悉该困难。

编辑: 既然你升级了你的问题,让我升级我的答案,这里是工作 OPL 代码来解决你的问题。我会使用 OPL,因为我不懂 AMPL,但是这两种语言非常相似,您可以轻松翻译。

using CPLEX;

int nbShifts = ...;
int nbDays = ...;
int nbEmpl = ...;

range sRng = 1..nbShifts; // for indexing                                                           
range dRng = 1..nbDays;
range eRng = 1..nbEmpl;

int shiftsWorked[eRng] = ...;  // number of shifts each employee works                              
int shiftsRequired[dRng][sRng] = ...;  // number of shift s required on day d                       

dvar int Assignments[eRng][dRng][sRng] in 0..1; // boolean matrix, 1=working 0=not working          

subject to  {

  // work at most 1 shift per day                                                                   
  forall(e in eRng, d in dRng)
    (sum(s in sRng) Assignments[e][d][s]) <= 1;

  // "vertical" constraint                                                                          
  forall(d in dRng, s in sRng)
    shiftsRequired[d][s] == (sum(e in eRng) Assignments[e][d][s]);

  // "horizontal" constraint                                                                        
  forall(e in eRng)
    (sum(d in dRng, s in sRng) Assignments[e][d][s]) == shiftsWorked[e];

}

// to print out A, in nicer format                                                                    
execute {
  write("\n");
  var flag;
  for (var e=1; e <= nbEmpl; e++) {
    for (var d=1; d <= nbDays; d++) {
      flag=0;
      for (var s=1; s <= nbShifts; s++) {
        if (Assignments[e][d][s] == 1) {
          flag=1;
          write(" S",s);
        }
        if (s == nbShifts && flag==0) write(" __");
      }
    }
    write("\n");
  }

}

您可以使用这样的 .dat 文件运行此代码:

nbShifts = 4;
nbDays = 7;
nbEmpl = 4;
shiftsWorked = [ 5 5 5 5 ];
shiftsRequired = [[3 0 0 1] [1 1 0 0] [0 0 1 1] [1 1 1 1] [0 0 0 0] [1 0 0 3] [0 2 2 0]];

并在不到一秒的时间内得到以下输出:

 S1 __ S3 S4 __ S4 S3
 S1 __ S4 S3 __ S4 S3
 S1 S2 __ S2 __ S4 S2
 S4 S1 __ S1 __ S1 S2

我希望当我开始我的问题时有人会告诉我这个;)

【讨论】:

    【解决方案2】:

    你看过Drools Planner(开源ASL,Java)吗? 有一个护士排班示例(= 员工轮班排班),与您正在做的非常相似,并且充满了限制。

    【讨论】:

      【解决方案3】:

      正如 cmets 所暗示的,这是一个机械时间表——对于人类,我们需要更多的输入。此外,这个“遗传算法”对于这项任务来说有点太高了。您可以使用数组/对象、迭代、配置设置和递归来做到这一点。

      你使用什么语言?

      【讨论】:

        【解决方案4】:

        我用 C# 写了一个简单的算法,可以解决在同一给定时间内教师、房间和讲座之间的 0 冲突的时间表问题。它的想法很简单:1-为每个老师生成可能的讲座(老师+时间段)。 2 - 为每个房间(房间+时间段)生成可能的讲座。 3- 从给定的teacher_periods 列表中随机抽取一个周期并检查两件事。 a - 这个随机周期是否存在于房间周期中? b - 这个随机时间不是由同一班学生参加的吗??如果这两个条件都成立,那么你必须做 3 件事: 1- 选择一个具有相同时期的房间并将其添加到解决方案中(在解决方案列表中)。 2- 从教师时段和房间时段列表中删除这段时间。否则,重复该过程。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-20
          • 1970-01-01
          相关资源
          最近更新 更多