打编程之026:职员时序安排模型
打编程之026:职员时序安排模型
这是一个经典的循环排班问题,也称为覆盖问题。
打编程系列里的数据和代码都被全部共享出来,没有额外的限制!
职员时序安排问题 是不同于之前的打编程之019:人员排班问题, 这个是更简单的一类问题,只有两个简单的要求,一是员工不能连续工作5天,二是需要满足一天的用工数量!
问题描述
一项工作一周七天都需要有人,每天(周一至周日)所需的最少职员数见下表:
| 周一 | 周二 | 周三 | 周四 | 周五 | 周六 | 周日 |
|---|---|---|---|---|---|---|
| 20 | 16 | 13 | 16 | 19 | 14 | 12 |
-
每个员工每周上班 5 天,且必须是连续的 5 天(余下的 2 天休息)。
-
要求:安排最少的员工总数,使得每天的人员安排满足/超过需求。
试求每周所需最少的职员数,并给出安排.
LINGO求解
我算是理解了,为什么那么多人选择LINGO来求解一些优化问题了。简单,易于上手编程,不需要注重背后的算法的选择,只需要鼠标点击操作即可,而且还有丰富的函数可用。
尤其是在每年的数学建模竞赛中,那是求解优化问题的首先选择!
之前的文章已经详细介绍了LINDO系列的算法:
为了图方便快捷,你也可以使用LINGO来处理,其代码如下(复制到LINGO中,运行即可!):
model:
!定义集合;
sets:
days/Mon..Sun/:required,start;
endsets
!输入数据;
data:
!每天所需的最少职员数;
required=20 16 13 16 19 14 12;
enddata
!最小化每周所需职员数;
min=@sum(days:start);
!约束条件:连续工作5天;
@for(days(J):
@sum(days(I)|I#le#5:
start(@wrap(J+I+2,7)))>=required(J));
end
其中,LINGO中的函数:
@WRAP(INDEX, LIMIT) 返回的是 INDEX - K * LIMIT, 其中K是一个整数,它使得返回值落到[1,LIMIT]上;

得到的结果是:
START( MON) = 8.000000
START( TUE) = 2.000000
START( WED) = 0.000000
START( THU) = 6.000000
START( FRI) = 3.000000
START( SAT) = 3.000000
START( SUN) = 0.000000
可以计算得到,一共有 $22$ 位员工!
优化模型
没有明确有多少个职员,只是要求:
- 每个职员一周连续工作5天,
- 满足每天的用工需求,
然后问每周所需最少的职员数!
值得注意的是:这好像是问最少招聘多少个职员,才能满足生产需求!
1、第一个急需要解决的问题:未知变量的设置!
首先,把哪个数据设置为未知变量 $x$?
根据要求,我们可以设置未知变量:
-
$x_1$: 周一开始连上 5 天(周一~周五)的员工数
-
$x_2$: 周二开始 (周二~周六)的员工数
-
$x_3$: 周三开始 (周三~周日)的员工数
-
$x_4$: 周四开始 (周四~下周一)的员工数
-
$x_5$: 周五开始 (周五~下周二)的员工数
-
$x_6$: 周六开始 (周六~下周三)的员工数
-
$x_7$: 周日开始 (周日~下周四)的员工数
详细的解释如下:
| 变量 | 开始工作日 | 连续工作日区间 | 含义说明 |
|---|---|---|---|
| x₁ | 周一 | 周一 ~ 周五 | 周一开始连上5天的员工数 |
| x₂ | 周二 | 周二 ~ 周六 | 周二开始连续5天上班的员工数 |
| x₃ | 周三 | 周三 ~ 周日 | 周三开始连续5天上班的员工数 |
| x₄ | 周四 | 周四 ~ 下周一 | 周四开始连续5天上班的员工数 |
| x₅ | 周五 | 周五 ~ 下周二 | 周五开始连续5天上班的员工数 |
| x₆ | 周六 | 周六 ~ 下周三 | 周六开始连续5天上班的员工数 |
| x₇ | 周日 | 周日 ~ 下周四 | 周日开始连续5天上班的员工数 |
2、第二个急需要解决的问题:未知变量的约束条件!
也就是要解决,每天的需求人数。我们首先看一看周一的情况,其需求人数为$20$. 于是,我们需要统计在周一工作的员工,再根据变量的设置含义,我们得到,
周一上班人数约束:
$x_1 + x_4 + x_5 + x_6 + x_7 \geq 20$.
同理,我们可得到周二上班人数约束:
$x_1 + x_2 + x_5 + x_6 + x_7 \geq 16$
周三上班人数约束:
$x_1 + x_2 + x_3 + x_6 + x_7 \geq 13$
周四上班人数约束:
$x_1 + x_2 + x_3 + x_4 + x_7 \geq 16$
周五上班人数约束:
$x_1 + x_2 + x_3 + x_4 + x_5 \geq 19$
周六上班人数约束:
$x_2 + x_3 + x_4 + x_5 + x_6 \geq 14$
周日上班人数约束:
$x_3 + x_4 + x_5 + x_6 + x_7 \geq 12$
3、第二个容易解决的问题:目标函数的表达式!
根据题设“安排最少的员工总数”,我们得到目标函数为:
$\max Z = x_1 + x_2 + x_3 + x_4 + x_5 + x_6 + x_7$
于是,我们得到如下的优化模型:
$$
\begin{aligned}
\max Z = x_1 + x_2 + x_3 + x_4 + x_5 + x_6 + x_7 \
\rm{s.t} ~
\begin{cases}
x_1 + x_4 + x_5 + x_6 + x_7 \geq 20 \
x_1 + x_2 + x_5 + x_6 + x_7 \geq 16 \
x_1 + x_2 + x_3 + x_6 + x_7 \geq 13\
x_1 + x_2 + x_3 + x_4 + x_7 \geq 16 \
x_1 + x_2 + x_3 + x_4 + x_5 \geq 19 \
x_2 + x_3 + x_4 + x_5 + x_6 \geq 14 \
x_3 + x_4 + x_5 + x_6 + x_7 \geq 12
\end{cases}
\end{aligned}
$$
模型求解
首先,数据准备如下:
#定义个类型为 String 的数据
Weekc=["周一";"周二";"周三";"周四";"周五";"周六";"周日"];
Week=["Monday";"Tuesday";"Wednesday";"Thursday";"Friday";"Saturday";"Sunday"];
#每天需求员工数量
D = [20;16;13;16;19;14;12]
其次,建立优化模型
# 导入建模语言
using JuMP
# 导入混合整数线性求解器
using HiGHS
# 建立具体的优化模型
DBS26 = Model(HiGHS.Optimizer)
最后,构建变量、约束条件和目标函数
# 创建 整数 变量
@variable(DBS26,x[Week],Int);
# 约束条件
@constraint(DBS26,MaxCap,
sum( x[i]*W[i] for i in Week ) <= M);
# 增加目标函数
@objective(DBS25,Min,
sum( x[i] for i in Week ) );
接下来,我们求解 0-1 背包问题
# 求解模型
optimize!(DBS26)
# 输出结果
value.(x)
结果是,
julia> value.(x)
5-element Vector{Float64}:
1.0
1.0
1.0
0.0
1.0
以上是利用软件求解的,当然了,也可以采取其他算法来求解,我们后续待续.....
如有疑问,尽可联系
boyogala@outlook.com

本文由mdnice多平台发布
浙公网安备 33010602011771号