【问题标题】:MiniZinc does not find a solution to the scheduling problemMiniZinc 没有找到调度问题的解决方案
【发布时间】:2019-02-18 08:11:01
【问题描述】:

我在使用 MiniZinc 寻找解决方案时遇到问题。

任务: 有必要为员工制定轮班时间表。 一天有三班:白天(D),晚上(E)和晚上(N)。 有必要制定一个最佳时间表,尽可能避免不良情况:

  • 避免单班(两次休息之间一班)

  • 避免单次休息(shift、break、shift)

  • 避免双中断(shift、break、break、shift)

  • 上完夜班后应该放一整天假(连续三个休息时间)

为了找到解决方案,我尽量减少不良情况的数量。 当我开始计算时,MiniZinc 显示了几个中间变量,但没有找到最终解决方案。

是否有可能以某种方式优化计算?

include "regular.mzn"; 
int: n = 21;   
int: m = 6;

set of int: D = 1..n;
set of int: E = 1..m;

% Number of employees per shift
                         %|Sun    |Mon    |Tue      |Wen      |Thur   |Fri     |Sat    |
array[D] of int: SHIFTS = [2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1];
                         /*2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1,
                           2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1,
                           2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2];*/

% The range of the number of shifts per employee for the period ([|from, to)                         
array[E, 1..2] of int: DC_SHIFTS = [|0, 10 %emp1
                                    |0, 10 %emp2
                                    |0, 10 %emp3
                                    |0, 10 %emp4
                                    |0, 10 %emp5
                                    |0, 10 %emp6
                                    |];

%-------------------------------------------------
% Variables
%-------------------------------------------------

array[E, D] of var 1..4: X;
% Counters of avoidable situations
var int: OS_PENALTY; % break, shift, break (single shift)
var int: NS_PENALTY; % night shift, not break, not break, not break (full day off after a night shift)
var int: DS_PENALTY; % shift, break, break, shift (two breaks between shifts)
var int: OO_PENALTY; % shift, break, shift (one break between shifts)

%-------------------------------------------------
% Constraints
%-------------------------------------------------

constraint
  forall(d in D)(
      sum(e in E)(bool2int(X[e, d] != 4)) = SHIFTS[d]
  );

constraint
  forall(e in E)(
      sum(d in D)(bool2int(X[e, d] != 4)) >= DC_SHIFTS[e, 1]
      /\
      sum(d in D)(bool2int(X[e, d] != 4)) < DC_SHIFTS[e, 2]
  );

constraint
  forall(d in D)(
      if d mod 3 = 1 then forall(e in E)(X[e, d] = 1 \/ X[e, d] = 4) else
      if d mod 3 = 2 then forall(e in E)(X[e, d] = 2 \/ X[e, d] = 4) else
      forall(e in E)(X[e, d] = 3 \/ X[e, d] = 4) endif endif
  );


NS_PENALTY = sum(e in E, d in D where d < max(D) - 2)(bool2int(
    X[e, d] = 3 \/ (X[e,d+1] != 4 /\ X[e,d + 2] != 4 /\ X[e,d + 3] != 4)
));

DS_PENALTY = sum(e in E, d in D where d < max(D) - 2)(bool2int(X[e, d] != 4 \/ X[e, d + 1] = 4 \/ X[e, d + 2] = 4 \/ X[e, d + 3] != 4));

OS_PENALTY = sum(e in E, d in D where d < max(D) - 1)(bool2int(X[e, d] = 4 /\ X[e, d + 1] != 4 /\ X[e, d + 2] = 4));

OO_PENALTY = sum(e in E, d in D where d < max(D) - 1)(bool2int(X[e, d] != 4 \/ X[e, d + 1] = 4 \/ X[e, d + 2] != 4));

%-------------------------------------------------
% Solve
%-------------------------------------------------

solve minimize OS_PENALTY + NS_PENALTY + DS_PENALTY + OO_PENALTY;

%-------------------------------------------------
% Output
%-------------------------------------------------

array[1..4] of string: rest_view = ["D", "E", "N", "-"];

output 
[ 
   rest_view[fix(X[e, d])] ++
   if d = n then "\n" else "" endif
   | e in E, d in D
];

【问题讨论】:

  • 如果这是您的选择,在 MiniZinc IDE 中切换求解器到 OSICB 会在一秒钟内找到最佳解决方案。
  • 我试图通过限制变量域、使用let 来避免重新计算总和、省略bool2int() 等来调整模型。所有这些都没有区别。 ChuffedGecode 无法找到低于 217 罚金的解决方案。OSICBC 得到罚金 213,并在 873 毫秒内将其诊断为最小值。
  • @m-dedlovsky 看起来有些惩罚表达式计算错误。我相信以下内容会正确匹配您的描述:NS_PENALTY = sum(e in E, d in D where d &lt; max(D) - 2)(bool2int( X[e, d] = 3 /\ (X[e,d+1] != 4 \/ X[e,d + 2] != 4 \/ X[e,d + 3] != 4) ));DS_PENALTY = sum(e in E, d in D where d &lt; max(D) - 2)(bool2int(X[e, d] != 4 /\ X[e, d + 1] = 4 /\ X[e, d + 2] = 4 /\ X[e, d + 3] != 4));OO_PENALTY = sum(e in E, d in D where d &lt; max(D) - 1)(bool2int(X[e, d] != 4 /\ X[e, d + 1] = 4 /\ X[e, d + 2] != 4));

标签: minizinc


【解决方案1】:

我建议对您的模型进行以下更改:

X 的声明更改为array[E, D] of var 0..1: X;,其中0 表示中断,1 表示移位。无论是白班、晚班还是夜班都在输出部分处理,其中的结果被转换为显示班次类型,如if fix(X[e, d]) == 0 then "-" else rest_view[1 + (d-1) mod 3] endif

使用全局变量重写约束,例如:

import "globals.mzn"; 
constraint
  forall(d in D)(
      exactly(SHIFTS[d], col(X, d), 1)
      %sum(e in E)(bool2int(X[e, d] != 0)) = SHIFTS[d]
  );

constraint
  forall(e in E)(
      global_cardinality_low_up(row(X, e), [1], [DC_SHIFTS[e, 1]], [DC_SHIFTS[e, 2] - 1])
      %sum(d in D)(bool2int(X[e, d] != 0)) >= DC_SHIFTS[e, 1]
      %/\
      %sum(d in D)(bool2int(X[e, d] != 0)) < DC_SHIFTS[e, 2]
  );

%constraint
%  forall(d in D)(
%      if d mod 3 = 1 then forall(e in E)(X[e, d] = 1 \/ X[e, d] = 4) else
%      if d mod 3 = 2 then forall(e in E)(X[e, d] = 2 \/ X[e, d] = 4) else
%      forall(e in E)(X[e, d] = 3 \/ X[e, d] = 4) endif endif
%  );

将惩罚改写如下:

NS_PENALTY = sum(e in E, d in 1..n - 3 where d mod 3 = 0)(bool2int(
    X[e, d] = 1 /\ (sum(i in 1..3)(X[e,d+i]) > 0)
));

DS_PENALTY = sum(e in E, d in 1..n - 3)(bool2int(X[e, d] != 0 /\ X[e, d + 1] = 0 /\ X[e, d + 2] = 0 /\ X[e, d + 3] != 0));

OS_PENALTY = sum(e in E, d in 1..n - 2)(bool2int(X[e, d] = 0 /\ X[e, d + 1] != 0 /\ X[e, d + 2] = 0));

OO_PENALTY = sum(e in E, d in 1..n - 2)(bool2int(X[e, d] != 0 /\ X[e, d + 1] = 0 /\ X[e, d + 2] != 0));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-04
    • 2023-04-10
    • 1970-01-01
    • 2017-07-30
    • 1970-01-01
    相关资源
    最近更新 更多