You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Google OR-Tools的志愿者排班:如何实现连续工作日偏好?

志愿者排班系统:连续工作日偏好的实现技巧

核心思路是给“非连续排班导致的额外出行”添加惩罚项,让模型优先选择连续天数更多的方案——因为连续排班的总惩罚更低,会被目标函数优先选中。

具体实现步骤

1. 定义辅助变量

针对每个志愿者和每一天,定义start[v,d]布尔变量:表示志愿者v在第d天开启了一个新的工作周期(即当天上班,且前一天休息;第一天上班直接算开启新周期)。这个变量的取值直接对应一次出行行为。

2. 添加约束关联排班变量

通过约束确保start[v,d]的取值逻辑正确:

  • 第一天:若志愿者当天上班,则start[v,0] = 1,否则为0
  • 后续天数:仅当当天上班且前一天休息时,start[v,d] = 1

3. 加入目标函数的惩罚项

给每个start[v,d]设置一个惩罚系数(可根据业务优先级调整),将所有start变量的惩罚总和加入原目标函数,让模型最小化总惩罚(即最小化出行次数)。

C#代码示例

// 假设x[v,d]是已定义的布尔变量,表示志愿者v在第d天是否上班
// 初始化参数
int totalDays = 5; // 示例总天数
int volunteerCount = 10; // 示例志愿者数量
int startPenalty = 10; // 出行惩罚系数,值越大越优先连续排班

// 定义start变量字典
var startVars = new Dictionary<(int Volunteer, int Day), BoolVar>();

foreach (int v in Enumerable.Range(0, volunteerCount))
{
    // 处理第一天的start逻辑
    startVars[(v, 0)] = model.NewBoolVar($"start_v{v}_d0");
    model.Add(startVars[(v, 0)] == x[v, 0]);

    // 处理后续天数的start逻辑
    foreach (int d in Enumerable.Range(1, totalDays - 1))
    {
        startVars[(v, d)] = model.NewBoolVar($"start_v{v}_d{d}");
        // 约束:仅当d天上班且d-1天休息时,start为1
        model.Add(startVars[(v, d)] >= x[v, d] - x[v, d - 1]);
        model.Add(startVars[(v, d)] <= x[v, d]);
        model.Add(startVars[(v, d)] <= 1 - x[v, d - 1]);
    }
}

// 计算出行惩罚总和
var startPenaltySum = LinearExpr.Sum(startVars.Values.Select(var => var * startPenalty));

// 更新目标函数,加入出行惩罚
model.Minimize(objBoolSum + objIntSum + startPenaltySum);

关键调整点

  • 惩罚系数startPenalty:如果希望减少出行的优先级高于班次覆盖率,将该值设得比低覆盖率的惩罚系数大;反之则调小,确保模型优先级符合业务需求。
  • 扩展优化:如果需要进一步鼓励更长的连续排班(比如3天连续优于2天连续),可以额外添加针对“短连续周期”的惩罚,但仅通过最小化start变量的方式,已经能实现你要求的排班优先级:[Yes, Yes, Yes, No, No](1次出行)< [Yes, No, Yes, Yes, No](2次出行)< [Yes, No, Yes, No, Yes](3次出行)。

内容的提问来源于stack exchange,提问作者CragMonkey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 21:50:11