学校时间表示例显示了与我需要解决的问题不同的问题。
问题是:
让我们上三门课:数学,英语,历史
所有这些课程都提供多个时隙(并行),学生可以从中选择一个。
让我们说:
数学:星期一: 9:00 - 10:00,星期二: 10:00 - 11:00 中文:星期一:9:00-10:00,星期二: 11:00 - 12:00,14:00 - 15:00,星期五: 16:00 - 17:00 历史:星期二: 10:00 - 11:00,星期五: 10:00 - 11:00
我想为每门课程找出最好的时间安排。我说的最好,是指差距最小的那个,更重要的是,让你有最多空闲时间的那个。
该示例问题的最佳解决方案可能如下
星期二:数学:9:00-10:00,历史: 10:00 - 11:00,英语: 11:00 - 12:00
没有空档,同时给出4天的空闲时间。
这在OptaPlanner中是可能的,还是应该使用不同的解决方法?我注意到Lesson
对象只有一个TimeSlot
,而不是一个列表,这使我认为这种时间表优化是不支持的。
发布于 2022-03-22 16:20:21
从描述上看,你的问题似乎是“学生计划自己的时间表”(而学校时间表则是“教师为所有学生制定学校时间表”)。
我会这样做:
@PlanningEntity
public class CourseSection {
private List<TimeSlot> availableTimeslots;
@PlanningId // needed for forEachUniquePair
private String courseSectionIdentifier;
@PlanningVariable(valueRangeProviderRefs = {"timeslotRange"})
private TimeSlot selectedTimeslot;
@ValueRangeProvider(id="timeslotRange")
public List<TimeSlot> getTimeslotRangeForCourse() {
return availableTimeslots;
}
// getters and setters ...
}
这利用了规划实体上的值范围提供程序,这意味着每个计划实体都有自己的值范围(并且不存在的课程TimeSlot将不会被尝试)。
我使用了CourseSection,因为课程可以分成多个部分(1次讲座+2次教程,2次讲座等等),每个部分都有一个CourseSection。(如果该课程只有一个讲座部分,那么只有一个CourseSection,如果该课程是一个讲座+教程,则有两个CourseSections等等)。
对于最小间隙约束,我将使用实验性的连续间隔约束收集器。要使用它,您要么需要将OptaPlanner实例添加为maven依赖项,要么需要添加从示例的源代码中复制它;一旦我们确定了API (它仍在试验阶段可能会发生变化),它最终将被移动到ConstraintCollectors中。对于连续的interval约束收集器,它将如下所示:
Constraint minimizeGaps(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(CourseSection.class)
.groupBy(section -> section.getSelectedTimeslot().getDayOfWeek(),
ExperimentalConstraintCollectors.consecutiveTemporalIntervals(
section -> section.getSelectedTimeslot().getStartTime(),
section -> section.getSelectedTimeslot().getEndTime()))
.flattenLast(ConsecutiveIntervalInfo::getBreaks)
.penalize("Minimize Gaps", HardMediumSoft.ONE_SOFT);
}
对于最大限度的空闲天数约束,我会将其写为“最小化工作日”,如下所示:
Constraint minimizeWorkingDays(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(CourseSection.class)
.groupBy(section -> section.getSelectedTimeslot().getDayOfWeek())
.penalize("Minimize Working Days", HardMediumSoft.ONE_MEDIUM);
}
最后,我们需要确保没有两个课程部分重叠:
Constraint noOverlappingCourseSections(ConstraintFactory constraintFactory) {
return constraintFactory.forEachUniquePair(CourseSection.class,
Joiners.equal(section -> section.getSelectedTimeslot().getDayOfWeek()),
Joiners.overlapping(
section -> section.getSelectedTimeslot().getStartTime(),
section -> section.getSelectedTimeslot().getEndTime()))
.penalize("Overlapping sections", HardMediumSoftScore.ONE_HARD);
}
注意,在我提供的约束条件中,工作时间较短的解决方案总是比工作日更多的解决方案更可取,即使解决方案的天数较少,间隔时间为8小时。您可能需要对允许的最大间隙添加一个附加约束(可以使用检查IntervalBreak.getLength()
的筛选器来实现)。
https://stackoverflow.com/questions/71572097
复制相似问题