基于or-tools的人员排班问题建模求解(JavaAPI)
使用Java调用or-tools实现了阿里mindopt求解器的案例(https://opt.aliyun.com/platform/case)人员排班问题。
这里写目录标题
- 人员排班问题
- 问题描述
- 数学建模
- 编程求解(ortools+JavaAPI)
- 求解结果
人员排班问题
随着现在产业的发展,7*24小时服务的需要,人员排班的问题,逐渐成为了企业管理中的重要环节。人员排班在许多行业都具有广泛的应用价值,主要包括以下几个方面:
- 制造业:生产车间的人员分配、班次安排和轮班计划等,需要根据产线的工作要求和员工的技能特点进行合理的排班。
- 医疗行业:医院、诊所等机构需要对医生、护士等员工进行排班。
- 餐饮业:餐厅、咖啡馆等服务场所需要根据客流高峰期和低谷期合理安排员工的工作时间。
- 零售业:商场、超市等零售场所需要根据营业时间、客流量和节假日等因素进行人员排班。
- 旅游业:景区、酒店等旅游设施需要根据旅游旺季、淡季和客流量变化对员工进行排班。
- 客服中心:呼叫中心、在线客服等服务机构需要根据客户咨询需求进行员工排班。
总之,人员排班在各行各业都具有重要的实际应用价值,可以帮助企业和机构提高管理效率、降低成本,同时提升员工的工作满意度和整体效能。总之,人员排班在各行各业都具有重要的实际应用价值,可以帮助企业和机构提高管理效率、降低成本,同时提升员工的工作满意度和整体效能。
运筹学中的数学规划方法是计算人员排班问题的一个好方案。人员排班问题在建模时需要考虑多种约束条件,比如:
- 用工需求约束:根据各岗位的工作任务和生产要求,保证每个岗位在每个时间段内有足够的员工进行工作。
- 员工能力约束:不同岗位可能需要不同的技能和经验,需要确保安排到相应岗位的员工具备相关的能力和资质。
- 工作时间约束:员工的工作时间需要遵守相关法律法规,比如每天工作时间上限、休息时间要求等。此外,还需要考虑员工的工作时间偏好,如部分员工可能只能接受特定时间段的工作安排。
- 连续工作天数约束:为保证员工的工作质量和身体健康,通常要求连续工作天数不超过一定限制。以及员工在一定时间周期内有休假要求,需要确保他们的休假安排得到满足。
- 公平性约束:为保障员工的权益,要求在满足以上约束的前提下,尽量平衡各员工的工作时间和任务分配,避免出现工作负担不均衡的情况。
- 员工偏好:如每个员工有自己更喜欢的上班的时间、岗位、或者协作同事配合等。
我们需要考虑企业内各岗位的需求、员工的工作能力以及工作时间的限制等因素。此外,还需关注企业成本与员工满意度的权衡,以确保在合理控制成本的前提下,最大程度地提高员工的工作满意度。属于一个约束复杂,且多目标的问题。在用数学规划方法进行排班时,建议做一些业务逻辑简化问题,否则容易出现问题太大或者不可解的情况。
下面我们将通过一个简单的例子,讲解如何使用数学规划的方法来做人员排班。
问题描述
个公司有客服岗工作需要安排,不同时间段有不同的用户需求。该公司安排员工上班的班次有三种:早班8-16点、晚班16-24点和夜班0-8点。一周员工最多安排5天上班,最少休息2天。需要保障值班员工能满足需求,且要保障员工休息时间,如前一天安排晚班后,第二天不能安排早班。
请问怎么安排总上班的班次最少,此时的班表是什么样的?
数学建模
编程求解(ortools+JavaAPI)
复制代码不能直接运行,需要在IDEA pom.xml中导入阿帕奇读取csv文件的依赖,并且需要导入ortools的maven依赖。
数据可在文章开头阿里mindopt案例地址中获取。
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-csv</artifactId><version>1.7</version></dependency>
package main.java.mindoptdemo;import com.google.ortools.Loader;
import com.google.ortools.sat.*;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.IntStream;public class EmployeeSchedulingProblem {public int n_shifts;public int n_days;public int n_employees;int[] days;int[] shifts;int[] employees;int[][] demandOfEmployees;public static Logger logger = Logger.getLogger("myLogger");public int getDemandOfEmployees(int day, int shift) {return demandOfEmployees[day][shift];}public EmployeeSchedulingProblem() throws IOException {demandOfEmployees = this.readFile();employees = IntStream.range(0, n_employees).toArray();days = IntStream.range(0, n_days).toArray();shifts = IntStream.range(0, n_shifts).toArray();}public int[][] readFile() throws IOException {this.n_shifts = 0;try (Reader reader = Files.newBufferedReader(Paths.get("src/main/java/mindoptdemo/班次.csv"))) {Iterable<CSVRecord> records = CSVFormat.DEFAULT.parse(reader);records.iterator().next(); // 跳过第一行for (CSVRecord record : records) {String shift = (record.get(0)); // 星期1到星期7,索引为0,故-1n_shifts += 1;}} catch (IOException e) {logger.warning(e.getMessage());}// 调度周期:7天,3班倒this.n_days = (int) Files.lines(Paths.get(new File("src/main/java/mindoptdemo/需求人数.csv").getPath())).count() - 1;int[][] demandOfEmps = new int[n_days][n_shifts];// commons-csv读取csv文件,需要导入依赖try (Reader reader = Files.newBufferedReader(Paths.get("src/main/java/mindoptdemo/需求人数.csv"))) {Iterable<CSVRecord> records = CSVFormat.DEFAULT.parse(reader);records.iterator().next(); // 跳过第一行for (CSVRecord record : records) {int day = Integer.parseInt(record.get(0)) - 1; // 星期1到星期7,索引为0,故-1int morningShiftEmpNum = Integer.parseInt(record.get(1)); // 早班需要员工的数量int middleShiftEmpNum = Integer.parseInt(record.get(2)); // 中班需要员工的数量int nightShiftEmpNum = Integer.parseInt(record.get(3)); // 晚班需要员工的数量//保存至二维数组,某天某班次需要的员工数量demandOfEmps[day][0] = morningShiftEmpNum;demandOfEmps[day][1] = middleShiftEmpNum;demandOfEmps[day][2] = nightShiftEmpNum;this.n_employees += morningShiftEmpNum + middleShiftEmpNum + nightShiftEmpNum;}this.n_employees = (int) Math.ceil((double) (this.n_employees) / 5) + 1;} catch (IOException e) {logger.info(e.getMessage());}return demandOfEmps;}public void orToolssolve() {Loader.loadNativeLibraries();// 声明模型CpModel model = new CpModel();// 初始化决策变量Literal[][][] x = new Literal[n_employees][n_days][n_shifts];for (int n : employees) {for (int d : days) {for (int s : shifts) {x[n][d][s] = model.newBoolVar("shifts_n" + n + "d" + d + "s" + s);}}}// 约束:每天各个班次在岗的人数符合需求for (int day = 0; day < days.length; day++) {for (int shift = 0; shift < shifts.length; shift++) {LinearExprBuilder numShiftsWorked = LinearExpr.newBuilder();for (int empNum = 0; empNum < n_employees; empNum++) {numShiftsWorked.add(x[empNum][day][shift]);}model.addLinearConstraint(numShiftsWorked, this.getDemandOfEmployees(day, shift), n_employees);}}// 约束:每人每天最多只有一个班次for (int n : employees) {for (int d : days) {List<Literal> work = new ArrayList<>();for (int s : shifts) {work.add(x[n][d][s]);}model.addAtMostOne(work);}}// 约束:前一天是晚班的,第二天不能是早班for (int e : employees) {for (int d : days) {List<Literal> work = new ArrayList<>();work.add(x[e][d][2]);if (d == 6) {work.add(x[e][0][0]);} else {work.add(x[e][d + 1][0]);}model.addAtMostOne(work);}}// 约束:一周工作工作时间不能超过5天for (int empNum = 0; empNum < n_employees; empNum++) {LinearExprBuilder expr = LinearExpr.newBuilder();for (int day = 0; day < days.length; day++) {for (int shift = 0; shift < shifts.length; shift++) {expr.add(x[empNum][day][shift]);}}model.addLinearConstraint(expr, 0, 5);}// 目标:雇佣的员工最少,即有排班的班次总数最少LinearExprBuilder obj = LinearExpr.newBuilder();for (int n : employees) {for (int d : days) {for (int s : shifts) {obj.add(x[n][d][s]);}}}model.minimize(obj);// 求解CpSolver solver = new CpSolver();CpSolverStatus status = solver.solve(model);if (status == CpSolverStatus.OPTIMAL || status == CpSolverStatus.FEASIBLE) {System.out.printf("%-8s", " ");for (int d = 0; d < n_days; d++) {System.out.printf("\t%d", d + 1);}System.out.println();for (int e : employees) {System.out.printf("employee%d\t", e + 1);int shiftCount = 0;for (int d : days) {int shift = 0;for (int s : shifts) {if (solver.booleanValue(x[e][d][s])) {shift = s + 1;shiftCount += 1;}}System.out.printf("%d\t", shift);}System.out.printf("员工%d这周上%d个班次", e + 1, shiftCount);System.out.println();}} else {System.out.printf("No optimal solution found !");}}public static void main(String[] args) throws IOException {EmployeeSchedulingProblem esp = new EmployeeSchedulingProblem();esp.orToolssolve();}
}
求解结果
每个员工在那一天上第几个班,本文or-tools求解结果,如图所示,如员工1-周1-上夜班,员工2-周1-不上班;0不上班、1早班、2晚班、3夜班。

相关文章:

基于or-tools的人员排班问题建模求解(JavaAPI)
使用Java调用or-tools实现了阿里mindopt求解器的案例(https://opt.aliyun.com/platform/case)人员排班问题。 这里写目录标题 人员排班问题问题描述数学建模编程求解(ortoolsJavaAPI)求解结果 人员排班问题 随着现在产业的发展&…...

设备管理团队如何做好停机维护工作_基于PreMaint设备数字化平台
在现代工业生产中,设备的正常运行对于企业的生产效率和利润至关重要。而停机维护作为设备管理的重要环节,旨在确保设备的安全性、可靠性和性能稳定。本文将介绍停机维护的概念,讨论如何计划停机维护,并重点探讨如何通过PreMaint设…...

c++ qt--线程(二)(第九部分)
c qt–线程(二)(第九部分) 一.线程并发 1.并发问题: 多个线程同时操作同一个资源(内存空间、文件句柄、网络句柄),可能会导致结果不一致的问题。发生的前提条件一定是多线程下…...
企业数据泄露不断,深信服EDR助企业构建数据“安全屋”
随着数字时代不断发展,数据泄露问题愈发严峻,个人信息安全面临着严重的威胁。近日,加拿大电信巨头加拿大贝尔(Bell Canada)对外披露了一起大规模数据泄露事件,该公司承认黑客入侵其系统,并窃取了190万个用户电子邮件地址以及约1700个用户姓名及活跃电话号码信息,相关损失无法估…...
单线复用iptv影响网速吗?
IPTV单线复用对网速有影响吗?这是一个比较常见的问题。如果你家的局域网是老的100M局域网LAN的路由器,走单线复用会影响你上网速度。但是如果你家的局域网是千兆网络,IPTV单线复用叠加上去的这点流量算不上什么,可以认为不占用网速…...

C语言中常用的字符串处理函数(strlen、strcpy、strcat、strcmp)
文章目录 写在前面1. strlen1.1 函数介绍1.2 模拟实现 2. strcpy2.1 函数介绍2.2 模拟实现 3. strcat3.1 函数介绍3.2 模拟实现 4. strcmp4.1 函数介绍4.2 模拟实现 写在前面 本篇文章介绍了C语言中常用的字符串处理函数,包括strlen、strcpy、strcat和strcmp。文章…...

Suricata – 入侵检测、预防和安全工具
一、Suricata介绍 Suricata是一个功能强大、用途广泛的开源威胁检测引擎,提供入侵检测 (IDS)、入侵防御 (IPS) 和网络安全监控功能。它执行深度数据包(网络流量)检查以及模式匹配,在威胁检测中非常强大。 工作流程: 主…...

vscode 乱码解决
windows 10 系统 vs code 编译运行和调试 C/C_vscode windows编译_雪的期许的博客-CSDN博客 VS Code默认文件编码时UTF-8,这对大多数情况是没有问题的,却偏偏对C/C有问题。如果以UTF-8编码保存C/C代码,那么只能输出英文,另外使用…...
SpringCloud(37):Spring Cloud Alibaba 综合集成架构演示
Spring Cloud是一个较为全面的微服务框架集,集成了如服务注册发现、配置中心、消息总线、负载均衡、断路器、API网关等功能实现。而在网上经常会发现Spring Cloud与阿里巴巴的Dubbo进行选择对比,这样做其实不是很妥当,前者是一套较为完整的架构方案,而Dubbo只是服务治理与R…...

【单片机】15-AD和DA转换
1.AD转换及其相关背景知识 1.基本概念 1.什么是AD转换? A(A,analog,模拟的,D,digital,数字的) 现实世界是模拟的,连续分布的,无法被分成有限份;…...

基于FPGA的I2C读写EEPROM
文章目录 前言一、I2C协议1.1 I2C协议简介1.2 物理层1.3 协议层 二、EEPROM2.1 型号及硬件规格2.2 各种读写时序 三、状态机设计四、项目源码:五、实现效果参考资料 前言 本次项目所用开发板FPGA芯片型号为:EP4CE6F17C8 EEPROM芯片型号为:24L…...
Viva Employee Communications Communities部署方案
目录 Viva Employee Communications & Communities产品介绍 1. 沟通中心(Communications Center) 2. 新闻和公告(News and Announcements)...

WPF向Avalonia迁移(三、项目结构)
前提: Avalonia版本11.0.0 1.配置文件 1.1 添加配置文件 1.2 读取配置文件 添加System.Configuration.ConfigurationManager using Avalonia.Controls; using System.Configuration;namespace AvaloniaApplication7.Views {public partial class MainWindow : W…...

cvpr24写作模板pdfLaTex编译器注意点小结
文章目录 1 更改作者显示 Anonymous CVPR submission2 \label标签3 换行符// 与换列符&4 \medskip5 首行缩进6 插入图片6.1 单幅图片6.2 并排显示\hfill Reference https://cvpr.thecvf.com/Conferences/2024 1 更改作者显示 Anonymous CVPR submission 这一行开头加上% …...
windows版php扩展包下载
php8有些扩展需自己下载,像redis 看下phpinfo中的PHP Extension Build,确定自己的php版本 windows.php.net - /downloads/pecl/releases/...

计算机竞赛 题目:基于深度学习的中文汉字识别 - 深度学习 卷积神经网络 机器视觉 OCR
文章目录 0 简介1 数据集合2 网络构建3 模型训练4 模型性能评估5 文字预测6 最后 0 简介 🔥 优质竞赛项目系列,今天要分享的是 基于深度学习的中文汉字识别 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! &a…...
Django跨域访问 nginx转发 开源浏览器
Django跨域访问 https://blog.csdn.net/lonelysnowman/article/details/128086205 nginx转发 https://blog.csdn.net/faye0412/article/details/75200607/ 开源浏览器 https://www.oschina.net/p/chromiumengine 浏览器油猴开发 https://blog.csdn.net/mukes/article/detail…...

Docker Alist 在线网盘部署
文章目录 拉取镜像创建并运行查看容器自动生成的密码在浏览器中进行访问 挂载本地磁盘 拉取镜像 docker pull xhofe/alist-aria2创建并运行 # -v /data/alist:/opt/alist/data 挂载本地目录 docker run -d --restartalways -v /data/alist:/opt/alist/data -p 5244:5244 -e P…...

Jmeter吞吐量控制器使用小结
吞吐量控制器(Throughput Controller)场景: 在同一个线程组里, 有10个并发, 7个做A业务, 3个做B业务,要模拟这种场景,可以通过吞吐量模拟器来实现.。 添加吞吐量控制器 用法1: Percent Executions 在一个线程组内分别建立两个吞吐量控制器, 分别放业务A和业务B 吞吐量控制器采…...

3分钟轻松实现网关网口连接罗克韦尔AB CompactLogix系列PLC
目录 EG网关网口连接罗克韦尔AB CompactLogix系列PLC 一. 准备工作 1.1 在对接前我们需准备如下物品 1.2 EG20网关准备工作 1.3 PLC准备工作 二. EMCP平台设置 2.1 新增EG设备 2.2 远程配置网关 2.3 网关绑定 2.4 通讯参数设置 2.5 创建设备驱动 2.5.1 添加变量 2.…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...