场景:在大学的里,有不少社团组织会要组织中的成员值班,当然这个值班时间是学生无课的时间才会被安排值班。

假设现有如下需求:一天中有3个时间段要有人值班,每周周一到周五都要值班,就是共有15个值班段,每个时间段值班的人都不一样,现有40个学生,要求根据这些学生的无课表情况安排值班,要求每个值班段必须有两个人,每个人一周只值班一次(如果某一值班段只有一人无课,那该值班段就只能一人值班)。

小插一题,做一排列组合题:

有10个相同的糖果,颁给3个小人,要求每个人至少有2个糖果,问共有多少种分法?

(自行解答,2014年阿里实习生招有个这样的题:有10个相同的糖果,颁给3个小人,要求每个人至少有1个糖果,问共有多少种分法?)

排班算法设计的难点主要在于每个人的无课表都不一样,如果像上面的题那样的,不用根据每个人的无课表,每个人在任意一值班段都能值班,那就简单啦。

以下讲讲个人算法的设计:

1.  基于回溯法的遍历:(实现思路:当安排到第N个值班段时,发现没有满足条件的可以选,就回溯到第N-1个值班段重新安排,如果第N-1个值班段的人都试过但第N个值班段还是没有满足条件的可以选,就回溯到第N-2个值班段,以此类推不断回溯)

现将上面的问题数据量缩小下来分析下这个问题:

假设有三个值班段,三个人,根据这三个人的无课表情况给值班段安排人值班。

思路:

先在第一个值班段无课的人中选择一个人安排到该值班段值班,被安排过的人就被标志为被安排值班(flag为0表示未被安排,flag为1表示已被安排),就不能再被安排到其他值班段值班了,以此类推,安排完一个值班段就安排下一个值班段。

最好情况:

最好情况下就是安排到每个值班段都有人未被安排过值班的人,这样一次性所有就排完了,如下图:

(1、2、3表示值班段,每个值班段里的字母表示该值班段无课的人,如上面第1个值班段有A和B两个人无课,可以安排在该值班段值班)

A被安排到1值班段,

B被安排到2值班段,

C被安排到3值班段。

最坏情况:

如下图所示:

安排到第三个值班段时因为A已经被安排过值班,所以要回溯到第二个值班段重新安排,就给第二个值班段安排C值班,但此时第三个值班段还是没人可以值班,而第二个值班段的人也都遍历过了,所以此时就要回溯到第一个值班段重新安排,此时:

B被安排到1值班段,

C被安排到2值班段,

A被安排到3值班段。

上面的是基本思路,但如果对15个值班段,40个人来排班,考虑下最坏情况,如果刚好到第十五个值班段时没人可以值班,而最后回溯到第一个值班段重新遍历,那查找比较次数都会大大增多,所以最后还是没有采取这种方法。不过个人也没能递归实现这个算法,有空再研究研究。

2.  基于优先级的选择:(实现思路:安排值班时不是从第一个值班段顺序地安排到第十五个值班段,因为在15个值班段中,有些值班段无课的人比较多,此时的选择就比较多,而有此值班段无课的人很少,那么这个值班就要优先安排人值班,比如有个值班段只有两人无课,那就要先安排这两个人在该值班段值班,这是第一个优先级;每个人一周内无课的次数都不一样,有些人一周只有一两次无课的时间,而有些人一周有五六次无课的时间,在一个值班段选择谁在该值班段值班时优先选择无课次数少的,这是第二个优先级)

// 值班段类

public class DutyTime {

private String time;  // 值班时间

private List freeUsers = new ArrayList();  // 该时间段无课的人

private List dutyUsers = new ArrayList();  // 该时间段值班的人员

public DutyTime(){}

public DutyTime(String time) {

super();

this.time = time;

}

// 省略get set

}

// 人员

public class User {

private String name;

private int num;  // 该人一周无课时间段数

public User(){}

public User(String name) {

super();

this.name = name;

}

// 省略get set

}

/**

* 值班安排:

*  先为每个值班段安排一名人员值班(第一轮),安排一轮后再进行第二轮、第三轮

* 按优先级安排值班:

*  1.各个值班段可值班人员数少的优先安排值班

*  2.在一个值班段选择人员时,优先选择总无课次数少的人

*      注:人员在被安排后就会从该值班段中的无课人员集合中删除,这样之后就不用再遍历到;在一轮安排后开始下一轮时,每个值班段的排人顺序会重新调整(因为去掉了已被安排的人)

*

*/

public class Schedule3 {

public static void main(String[] args) {

User A = new User("A", 4);  // A一周有4个时间段无课

...

DutyTime time1 = new DutyTime("1");  // 第一个值班段

...

time1.getFreeUsers().add(A);

...

List dutyTimeList = new ArrayList<>();

dutyTimeList.add(time1);

...

for (int w = 0; w

// 排序,可用于值班的人数少的值班段排在前面,下面安排值班是可用于值班的人数少的值班段优先安排

dutyTimeList = dutyTimeSort(dutyTimeList);

// 遍历已排好序的值班段,为每个值班段安排值班人员

for (int i = 0; i

// 如果该值班段有无课的人才安排值班

if (dutyTimeList.get(i).getFreeUsers().size() > 0) {

// 得到的都是未被安排过值班的人,并排好序,总无课次数少的人排前面

List freeUserList = freeUserSort(dutyTimeList.get(i).getFreeUsers());

// 将可在该值班段值班的人安排到该值班段值班

dutyTimeList.get(i).getDutyUsers().add(freeUserList.get(0));

System.out.println(freeUserList.get(0).getName() + " 被安排到" + dutyTimeList.get(i).getTime() + "值班;该值班段现有"+dutyTimeList.get(i).getDutyUsers().size()+"人值班,"+freeUserList.get(0).getName()+"一周总无课次数为:"+freeUserList.get(0).getNum());

// 将被安排的人从各个值班段(有该人的值班段)中删除,下次不用再遍历

User delUser = freeUserList.get(0);

for (int j = 0; j

if (dutyTimeList.get(j).getFreeUsers().contains(delUser)) {

dutyTimeList.get(j).getFreeUsers().remove(delUser);

System.out.println("---"+delUser.getName()+"已从"+dutyTimeList.get(j).getTime()+"值班段删除,目前该值班段剩余未被安排人数有:"+dutyTimeList.get(j).getFreeUsers().size());

}

}

}else {

System.out.println(dutyTimeList.get(i).getTime()+"该值班段已无人可安排值班");

}

}

System.out.println("---------------------安排了一轮--------------------");

}

}

// 对某一值班段中无课的人进行排序(一周总无课次数少的人排在前面)

public static List freeUserSort(List freeUserList);

// 对值班段排序(可用于值班的人数少的值班段排在前面)

public static List dutyTimeSort(List dutyTimeList);

}

使用这种方法实现排班只能生成一张值班表,但现实中根据总的无课表是可以排出不同方案的值班表的,以上的算法小编只是在满足个人项目需求的情况下设计的,并不是通用的,小编查过许多高校的教授发表的关于排课算法实现的论文,那些情况就更加复杂了,各种回溯各种优先级。

排课问题在70年代就证明是一个NP完全问题,即算法的计算时间是呈指数增长的,这一论断确立了排课问题的理论深度。对于NP问题完全问题目前在数学上是没有一个通用的算法能够很好地解决。

Author:顾故

Sign:别输给曾经的自己

排班算法 java_【算法】基于优先级的排班算法实现相关推荐

  1. 三维图形几何变换算法实验_基于深度学习的三维重建算法综述

    点击上方"计算机视觉life",选择"星标" 快速获得最新干货 00 前言 目前,三维重建技术已在游戏.电影.测绘.定位.导航.自动驾驶.VR/AR.工业制造以 ...

  2. 清华大学开源迁移学习算法库:基于PyTorch实现已有算法

    点上方蓝字计算机视觉联盟获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:机器之心 AI博士笔记系列推荐 周志华<机器学习> ...

  3. 栅格法路径算法C语言,基于地图栅格与QPSO算法结合的机器人路径规划方法与流程...

    本发明属于机器人路径规划领域,提出一种基于地图栅格与QPSO结合的机器人路径规划方法. 背景技术: 移动机器人路径规划是寻找一条无碰撞的可行路径问题的方法.近些年,群智能优化算法逐渐成为移动机器人路径 ...

  4. rrt算法流程图_基于RRT的运动规划算法综述

    基于 RRT 的运动规划算法综述 1. 介绍 在过去的十多年中, 机器人的运动规划问题已经收到了大量的关注, 因为机器人开始成 为现代工业和日常生活的重要组成部分. 最早的运动规划的问题只是考虑如何移 ...

  5. 推荐算法概述(基于用户的协同过滤算法、基于物品的协同过滤算法、基于内容的推荐算法)

    "无意中发现了一个巨牛的人工智能教程,忍不住分享一下给大家.教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家.点这里可以跳转到教程." 目前推 ...

  6. 连通域最小外接矩形算法原理_基于分割的文本检测算法之PSENet/PAN/DBNet

    1. 文本检测难点 文本内包含文本,艺术字体,任意方向 ,曲线文字 ,多语言,其他环境因素等是文本检测中的难点 2. 分割 问题1: 语义分割模型是对pixel进行分类,所以理论上讲,可以检测不规则的 ...

  7. 8种排序算法 java_必须知道的八大种排序算法【java实现】

    一.冒泡排序 冒泡排序是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成. ...

  8. AI算法和笔记 | 基于深度学习和传统算法的人体姿态估计

    点击蓝色"AI专栏"关注我哟 选择"星标",重磅干货,第一时间送达 这是站长的第 41 篇原创优质长文, 前几天站长写的一篇的文章[基于深度学习算法和传统立体匹 ...

  9. 通用高校排课算法研究----3.基于时间片优先级排课算法

    3 基于时间片优先级排课算法描述与分析 排课问题实质上是时间.教师.班级.教室.课程这五维关系的冲突问题,要合理的解决这个问题首先要了解排课中的一些基本原则以及排课的一些基本要求. 3.1排课中的基本 ...

最新文章

  1. mqtt 传文件断开连接的原因_mqtt 发送消息断开链接
  2. 随机森林(Random Forest)和梯度提升树(GBDT)有什么区别?
  3. 【转】二层交换机之间的跨网段访问
  4. 选择列表中的列……无效,因为该列没有包含在聚合函数或 GROUP BY 子句中
  5. 【2019暑假刷题笔记-链表】总结自《算法笔记》
  6. CycleGAN:图片风格,想换就换 | ICCV 2017论文解读
  7. QT的QRandomGenerator类的使用
  8. C++Builder中ListView控件用法和示例总结整理
  9. 【Linux】一步一步学Linux——exec命令(208)
  10. Hive _函数(系统内置函数、自定义函数、自定义UDF函数)
  11. halcon圆环完整度检测
  12. Ubuntu安装php
  13. 斗鱼实名认证 mysql_我告诉你斗鱼实名认证怎么取消
  14. 属性管理器没有Microsoft.Cpp.x64.user的解决办法
  15. 嵌入式系统基础——Unbuntu的初步使用
  16. 无线蜂窝通信模组是什么?
  17. js 时间运算,时间加减
  18. 很多人已经学会了应对恐惧和焦虑的秘诀
  19. NOSQL,MongoDB分布式集群架构
  20. 51单片机八人抢答器c语言,抢答器 - 基于51单片机 - 8人有程序较完整.doc

热门文章

  1. 广东省新型数据中心发展白皮书
  2. 自媒体人怎么修改视频的MD5值,实现很好地搬运
  3. Vue学习(二)动态绑定与事件监听
  4. android图案解锁功能的实现
  5. 【物联网硬件安全】二、固件分析-固件提取
  6. WannaCry勒索病毒分析过程**上**
  7. 在 GitHub 玩硬件——GitHub 热点速览 Vol.49
  8. sgi集群管理软件SMC安装步骤整理
  9. splint 编译安装
  10. Yii2本身自带实现用户注册、登录