OR-Tools员工排班优化:如何设置目标函数优先选择连续班次(支持单日多班次)
Awesome question! Let’s walk through how to adjust your OR-Tools employee scheduling model to meet your needs—allowing multiple shifts per day for employees, while guiding the model to prefer consecutive shift assignments (without making it a mandatory rule).
1. First: Enable Multiple Shifts per Day
This part is straightforward. You just need to modify your existing constraints:
- Remove any hard constraints that limit an employee to one shift per day (like
sum(shift_assigned[e,d,s] for s in shifts) <= 1). - Keep any necessary guardrails, though—for example, constraints that cap an employee’s total daily working hours (e.g.,
sum(shift_duration[s] * shift_assigned[e,d,s] for s in shifts) <= max_daily_hours).
Your core boolean variable shift_assigned[e,d,s] (1 = employee e is assigned shift s on day d) will now be allowed to have multiple 1 values for the same (e,d) pair.
2. The Key: Designing an Objective Function for Consecutive Shifts
To prioritize consecutive shifts without making them a hard rule, we’ll add a penalty cost to non-consecutive shift combinations. The model will minimize total cost, so it will naturally favor solutions with fewer (or no) non-consecutive shifts.
Step 1: Define Shift Time Attributes
First, map each shift to its start and end times (use minutes for precision if needed):
# Example: Shift name -> (start time in hours, end time in hours) shift_time_map = { "early_morning": (6, 10), "midday": (10, 14), "afternoon": (14, 18), "evening": (18, 22) }
Step 2: Add Penalties for Non-Consecutive Shifts
For each employee and day, we’ll check all pairs of shifts where the first ends before the second starts. If both shifts are assigned to the employee on that day and there’s a gap between them, we add a penalty to the total cost.
Here’s how to implement this in OR-Tools’ CP-SAT solver:
# Define how much we penalize each hour of gap between shifts # Higher values = stronger preference for consecutive shifts penalty_per_hour_gap = 15 total_cost = 0 # Keep your existing cost terms (e.g., overtime penalties, coverage gaps) here # ... # Add penalty for non-consecutive shift pairs for emp in employees: for day in days: # Get all valid shift pairs where shift1 ends before shift2 starts shift_pairs = [ (s1, s2) for s1 in shifts for s2 in shifts if shift_time_map[s1][1] < shift_time_map[s2][0] ] for s1, s2 in shift_pairs: # Calculate the gap between the two shifts gap_hours = shift_time_map[s2][0] - shift_time_map[s1][1] # Penalty only applies if both shifts are assigned to the employee that day # Boolean variables multiply to 1 only when both are true total_cost += gap_hours * penalty_per_hour_gap * shift_assigned[emp, day, s1] * shift_assigned[emp, day, s2] # Minimize the total cost model.Minimize(total_cost)
Step 3: Adjust the Penalty Strength
Tweak penalty_per_hour_gap to control how strongly the model prioritizes consecutive shifts:
- A large value (e.g., 50) will make the model almost always choose consecutive shifts unless no other feasible solution exists.
- A smaller value (e.g., 5) lets the model balance shift continuity with other priorities (like minimizing overtime or covering all required shifts).
3. Handling Multi-Shift Consecutive Chains
If an employee is assigned 3+ consecutive shifts (e.g., early_morning → midday → afternoon), the code above will automatically treat this as optimal. Each adjacent pair has a gap of 0 hours, so no penalty is added for those combinations.
内容的提问来源于stack exchange,提问作者marko

