如何编写Timefold约束实现员工任务分配的均匀分布惩罚逻辑?
任务均匀分配的Timefold约束实现问题
刚接触Timefold,接手了他人开发的简易规划引擎,现需实现约束以确保任务分配在员工间均匀分布。要求根据员工任务数与全局最小任务数的差值的平方进行惩罚,示例如下:
| 任务分布 | 惩罚值 |
|---|---|
| 1,1,1 | 0 |
| 5,5,5 | 0 |
| 5,1,1 | 16 |
| 5,1,0 | 26 |
当前编写的约束代码假设基准值为1,导致任务数均匀的场景(如5,5,5)也会被惩罚,需要找到获取全局最小任务数的方法,推测可借助groupBy逻辑解决,但暂未理清实现方式。
现有相关代码:
Employee类代码
class Employee { var assignedTasks: MutableList<TaskAssignment> fun getTaskCount(): Int { return assignedTasks.size } }
当前约束代码
return constraintFactory.forEach(Employee::class.java) .filter { employee -> employee.getTaskCount() > 1 } .penalize(HardMediumSoftLongScore.ofSoft(1)) { employee: Employee -> pow(employee.getTaskCount(), 2) } .asConstraint("Load balance the tasks per employee.")
解决方案
要实现符合要求的约束,核心是先获取全局所有员工的最小任务数,再基于该值计算惩罚。以下提供两种可行实现方式:
方式一:通过groupBy聚合全局最小值
return constraintFactory.forEach(Employee::class.java) // 将所有员工归为同一组,聚合得到全局最小任务数 .groupBy { _, _ -> 1 } .aggregate({ employee -> employee.getTaskCount() }, min()) // 关联每个员工,计算惩罚 .join(Employee::class.java) .filter { (minTaskCount, employee) -> employee.getTaskCount() > minTaskCount } .penalize(HardMediumSoftLongScore.ofSoft(1)) { (minTaskCount, employee) -> val difference = employee.getTaskCount() - minTaskCount difference * difference // 计算差值的平方 } .asConstraint("Load balance tasks evenly across employees.")
方式二:先定义全局最小任务数约束
// 先创建全局约束,获取所有员工的最小任务数 val globalMinTaskCount = constraintFactory.stream(Employee::class.java) .map { it.getTaskCount() } .min() .toGlobalConstraint() // 主约束逻辑 return constraintFactory.forEach(Employee::class.java) .filter { employee -> employee.getTaskCount() > globalMinTaskCount } .penalize(HardMediumSoftLongScore.ofSoft(1)) { employee -> val diff = employee.getTaskCount() - globalMinTaskCount diff * diff } .asConstraint("Load balance tasks per employee.")
逻辑说明
- 两种方式都会先计算全局范围内员工的最小任务数,避免了硬编码基准值的问题。
- 仅当员工任务数大于全局最小值时,才计算差值的平方作为惩罚值,确保任务分布均匀的场景(如5,5,5)不会产生惩罚,完全符合需求。
内容的提问来源于stack exchange,提问作者Mike Schilder
相关产品推荐
相关产品推荐

