欢迎大家来到IT世界,在知识的湖畔探索吧!
近期一个老客户过来咨询,在人员排班这里,原来是通过人工方式来进行的,但是由于人力资源有限,想要通过软件实现自动排班。排班自动化,一直是个难题,作者君连夜请教了AI助手,寻找有无快速可用的代码生成或者思路。
先上结果:本次使用的是腾讯元宝,元宝给出的代码运行报错,最后是以元宝的方案为基础,自行编写代码实现算法。
代码切片
// 员工类(包含所属岗位) public class Employee { private final String id; private final String name; private final String position; // 所属岗位 public Employee(String id, String name, String position) { this.id = id; this.name = name; this.position = position; } // Getter方法 public String getId() { return id; } public String getName() { return name; } public String getPosition() { return position; } @Override public String toString() { return "Employee{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", position='" + position + '\'' + '}'; } } public class ScheduleDateResult { private String group; private LocalDate date; private ShiftType shiftType; public ScheduleDateResult(String group, LocalDate date, ShiftType shiftType) { this.group = group; this.date = date; this.shiftType = shiftType; } public String getGroup() { return group; } public void setGroup(String group) { this.group = group; } public LocalDate getDate() { return date; } public void setDate(LocalDate date) { this.date = date; } public ShiftType getShiftType() { return shiftType; } public void setShiftType(ShiftType shiftType) { this.shiftType = shiftType; } @Override public String toString() { return group +","+date+","+shiftType; } }
欢迎大家来到IT世界,在知识的湖畔探索吧!
欢迎大家来到IT世界,在知识的湖畔探索吧! public class ScheduleGenerator { public List<ScheduleEntry> generate(ScheduleConfig config) { validateConfig(config); List<ScheduleEntry> allEntries = new ArrayList<>(); LocalDate startDate = config.getStartDate(); int daysInMonth = startDate.lengthOfMonth(); // 生成休息日 Map<Employee, Set<LocalDate>> restDaysMap = generateRestDays(config.getEmployees(), daysInMonth, startDate); // 初始化员工排班表(标记休息日,工作日为null) Map<Employee, Map<LocalDate, ShiftType>> employeeSchedules = initializeSchedules( config.getEmployees(), restDaysMap, daysInMonth, startDate ); // 按日分配班次 for (int day = 1; day <= daysInMonth; day++) { LocalDate date = startDate.plusDays(day - 1); assignDailyShifts(date, config, restDaysMap, employeeSchedules, allEntries); } validateFinalSchedule(allEntries, config, daysInMonth); return allEntries.stream() .sorted(Comparator.comparing(ScheduleEntry::getDate) .thenComparing(ScheduleEntry::getPosition) .thenComparing(ScheduleEntry::getEmployeeId)) .collect(Collectors.toList()); } private Map<Employee, Set<LocalDate>> generateRestDays(List<Employee> employees, int daysInMonth, LocalDate startDate) { Map<Employee, Set<LocalDate>> restDaysMap = new HashMap<>(); Random random = new Random(); for (Employee emp : employees) { Set<LocalDate> restDays = new HashSet<>(); int cycleOffset = random.nextInt(15); // 每个员工不同的周期偏移 for (int day = 1; day <= daysInMonth; day++) { LocalDate currentDate = startDate.plusDays(day - 1); int cyclePos = (day - 1 + cycleOffset) % 15; // 15天周期:工作6天(0-5)→ 休1天(6)→ 工作6天(7-12)→ 休2天(13-14) if (cyclePos == 6 || (cyclePos >= 13 && cyclePos <= 14)) { restDays.add(currentDate); } } restDaysMap.put(emp, restDays); } return restDaysMap; } private Map<Employee, Map<LocalDate, ShiftType>> initializeSchedules( List<Employee> employees, Map<Employee, Set<LocalDate>> restDaysMap, int daysInMonth, LocalDate startDate) { Map<Employee, Map<LocalDate, ShiftType>> schedules = new HashMap<>(); for (Employee emp : employees) { Map<LocalDate, ShiftType> empSchedule = new HashMap<>(); for (int day = 1; day <= daysInMonth; day++) { LocalDate date = startDate.plusDays(day - 1); empSchedule.put(date, restDaysMap.get(emp).contains(date) ? ShiftType.REST : null); } schedules.put(emp, empSchedule); } return schedules; } private void assignDailyShifts(LocalDate date, ScheduleConfig config, Map<Employee, Set<LocalDate>> restDaysMap, Map<Employee, Map<LocalDate, ShiftType>> employeeSchedules, List<ScheduleEntry> allEntries) { Map<String, List<Employee>> positionGroups = config.getEmployees().stream() .collect(Collectors.groupingBy(Employee::getPosition)); for (String position : config.getMinDay().keySet()) { List<Employee> positionEmps = positionGroups.getOrDefault(position, Collections.emptyList()); if (positionEmps.isEmpty()) continue; // 当日工作的员工(非休息) List<Employee> workingEmps = positionEmps.stream() .filter(emp -> !restDaysMap.get(emp).contains(date)) .collect(Collectors.toList()); // 前一天各员工的班次(用于连续校验) Map<Employee, ShiftType> prevDayShifts = new HashMap<>(); LocalDate prevDate = date.minusDays(1); for (Employee emp : workingEmps) { if (prevDate.getMonthValue() == date.getMonthValue() && prevDate.getYear() == date.getYear()) { // 前一天在当月内 prevDayShifts.put(emp, employeeSchedules.get(emp).get(prevDate)); } else { // 前一天跨月,视为休息 prevDayShifts.put(emp, ShiftType.REST); } } // 分配白班和夜班 assignShiftsForPosition(date, position, workingEmps, prevDayShifts, config.getMinDay().get(position), config.getMinNight().get(position), employeeSchedules, allEntries, config); } } private void assignShiftsForPosition(LocalDate date, String position, List<Employee> workingEmps, Map<Employee, ShiftType> prevDayShifts, int minDay, int minNight, Map<Employee, Map<LocalDate, ShiftType>> employeeSchedules, List<ScheduleEntry> allEntries, ScheduleConfig config) { // 分离不能上白班的员工(前一天白班) List<Employee> cannotDay = workingEmps.stream() .filter(emp -> prevDayShifts.get(emp) == ShiftType.DAY) .collect(Collectors.toList()); // 分离不能上夜班的员工(前一天夜班且不允许连续) List<Employee> cannotNight = workingEmps.stream() .filter(emp -> prevDayShifts.get(emp) == ShiftType.NIGHT && config.getMaxConsecutiveSameShift() == 0) .collect(Collectors.toList()); // 可用员工池 List<Employee> availableDay = new ArrayList<>(workingEmps); availableDay.removeAll(cannotDay); List<Employee> availableNight = new ArrayList<>(workingEmps); availableNight.removeAll(cannotNight); // 分配白班(优先满足最小人数) if (availableDay.size() < minDay) { throw new IllegalStateException(String.format( "岗位[%s]白班人数不足(需要%d,可用%d)", position, minDay, availableDay.size())); } Collections.shuffle(availableDay); for (int i = 0; i < minDay; i++) { Employee emp = availableDay.get(i); employeeSchedules.get(emp).put(date, ShiftType.DAY); allEntries.add(new ScheduleEntry(date, emp.getId(), position, ShiftType.DAY)); } // 分配夜班(优先满足最小人数) if (availableNight.size() < minNight) { throw new IllegalStateException(String.format( "岗位[%s]夜班人数不足(需要%d,可用%d)", position, minNight, availableNight.size())); } Collections.shuffle(availableNight); for (int i = 0; i < minNight; i++) { Employee emp = availableNight.get(i); employeeSchedules.get(emp).put(date, ShiftType.NIGHT); allEntries.add(new ScheduleEntry(date, emp.getId(), position, ShiftType.NIGHT)); } // 平衡剩余员工(简单轮询) balanceRemainingShifts(workingEmps, date, employeeSchedules, prevDayShifts, allEntries); } private void balanceRemainingShifts(List<Employee> workingEmps, LocalDate date, Map<Employee, Map<LocalDate, ShiftType>> employeeSchedules, Map<Employee, ShiftType> prevDayShifts, List<ScheduleEntry> allEntries) { List<Employee> unassigned = new ArrayList<>(); for (Employee emp : workingEmps) { if (employeeSchedules.get(emp).get(date) == null) { unassigned.add(emp); } } // 按前一天班次排序,优先分配相反班次 unassigned.sort(Comparator.comparing(emp -> prevDayShifts.getOrDefault(emp, ShiftType.REST))); int half = unassigned.size() / 2; for (int i = 0; i < half; i++) { Employee emp = unassigned.get(i); employeeSchedules.get(emp).put(date, ShiftType.NIGHT); allEntries.add(new ScheduleEntry(date, emp.getId(), emp.getPosition(), ShiftType.NIGHT)); } for (int i = half; i < unassigned.size(); i++) { Employee emp = unassigned.get(i); employeeSchedules.get(emp).put(date, ShiftType.DAY); allEntries.add(new ScheduleEntry(date, emp.getId(), emp.getPosition(), ShiftType.DAY)); } } private void validateConfig(ScheduleConfig config) { Set<String> positions = config.getEmployees().stream() .map(Employee::getPosition) .collect(Collectors.toSet()); if (!positions.equals(config.getMinDay().keySet()) || !positions.equals(config.getMinNight().keySet())) { throw new IllegalArgumentException("岗位配置不一致"); } for (String pos : positions) { long totalEmps = config.getEmployees().stream() .filter(emp -> emp.getPosition().equals(pos)) .count(); int required = config.getMinDay().get(pos) + config.getMinNight().get(pos); if (required > totalEmps) { throw new IllegalArgumentException(String.format( "岗位[%s]白班+夜班人数超过总员工数(需要%d,实际%d)", pos, required, totalEmps)); } } } private void validateFinalSchedule(List<ScheduleEntry> entries, ScheduleConfig config, int daysInMonth) { // 按日期和岗位统计班次人数 Map<LocalDate, Map<String, Map<ShiftType, Long>>> dailyStats = entries.stream() .collect(Collectors.groupingBy(ScheduleEntry::getDate, Collectors.groupingBy(ScheduleEntry::getPosition, Collectors.groupingBy(ScheduleEntry::getShift, Collectors.counting())))); // 检查每日人数是否达标 for (LocalDate date : dailyStats.keySet()) { Map<String, Map<ShiftType, Long>> posStats = dailyStats.get(date); for (String pos : posStats.keySet()) { Map<ShiftType, Long> shifts = posStats.get(pos); long dayCount = shifts.getOrDefault(ShiftType.DAY, 0L); long nightCount = shifts.getOrDefault(ShiftType.NIGHT, 0L); if (dayCount < config.getMinDay().get(pos)) { throw new IllegalStateException(String.format( "日期[%s] 岗位[%s]白班不足(需要%d,实际%d)", date, pos, config.getMinDay().get(pos), dayCount)); } if (nightCount < config.getMinNight().get(pos)) { throw new IllegalStateException(String.format( "日期[%s] 岗位[%s]夜班不足(需要%d,实际%d)", date, pos, config.getMinNight().get(pos), nightCount)); } } } // 检查连续同班次 Map<String, List<ScheduleEntry>> empEntries = entries.stream() .collect(Collectors.groupingBy(ScheduleEntry::getEmployeeId)); for (List<ScheduleEntry> empSchedule : empEntries.values()) { empSchedule.sort(Comparator.comparing(ScheduleEntry::getDate)); for (int i = 1; i < empSchedule.size(); i++) { ScheduleEntry prev = empSchedule.get(i - 1); ScheduleEntry curr = empSchedule.get(i); if (prev.getShift() == ShiftType.DAY && curr.getShift() == ShiftType.DAY) { throw new IllegalStateException(String.format( "员工[%s] 连续白班:[%s] → [%s]", prev.getEmployeeId(), prev.getDate(), curr.getDate())); } if (prev.getShift() == ShiftType.NIGHT && curr.getShift() == ShiftType.NIGHT) { throw new IllegalStateException(String.format( "员工[%s] 连续夜班:[%s] → [%s]", prev.getEmployeeId(), prev.getDate(), curr.getDate())); } } } } }
public class MyCstGenerator { // 排班计划 总天数 14天 // 休息 3天 // 排班策略: 固定周期+休息日缓冲 6,1,5,2 3,1,4,1,4,1 // 5,1,6,2 / * 逻辑: * 1、按照班次 白班、夜班、休息 三个排班状态,准备相同的组 * 2、每组最小人数需要满足班次排班的最少人数要求 * 3、休息日安排,排班周期内,保证休息日数量足够且不超出 * 4、排班策略: 固定周期+休息日缓冲 * 5、通过休息之后,主动切换排班方式,让其他组进入休息状态 * 6、通过先满足至少每天每个班次都有人员安排的情况下后,将多余的休息日转化为排班 * 7、将排班结果复制两个周期 * 8、截取想要输出的月份排班数据 * */ public void init(){ // // 员工数据(1个岗位,3名员工) String position = "客服"; List<Employee> employees = new ArrayList<>(); employees.add(new Employee("101", "张三", position)); employees.add(new Employee("102", "李四", position)); employees.add(new Employee("103", "王五", position)); int totalEmployeeCount = employees.size(); int shiftMinEmployeeCount = 1; // 两个班次 List<ShiftType> shiftTypeList = new ArrayList<>(); shiftTypeList.add(ShiftType.DAY); shiftTypeList.add(ShiftType.NIGHT); int shiftTypeCount = shiftTypeList.size(); if (totalEmployeeCount < shiftMinEmployeeCount * (shiftTypeCount + 1)) { throw new RuntimeException("安排的工人总人数 小于 (排班班次的分类数量 +1)* 班次安排最小人数 , 不满足排班要求"); } int scheduleRangeDays = 14; int restDaysInRange = 3; int workDaysInRange = scheduleRangeDays - restDaysInRange; if (restDaysInRange < shiftTypeCount) { throw new RuntimeException("安排的休息天数 小于 排班班次的分类数量"); } Map<Integer, ScheduleRule> scheduleRuleMap = new HashMap<>(); scheduleRuleMap.put(1, new ScheduleRule(1, ShiftType.DAY, 0)); scheduleRuleMap.put(2, new ScheduleRule(2, ShiftType.REST, 0)); scheduleRuleMap.put(3, new ScheduleRule(3, ShiftType.NIGHT, 0)); scheduleRuleMap.put(4, new ScheduleRule(4, ShiftType.REST, 0)); // 初始化排班策略 班次1 + 休息1 + 班次2 + 休息2 + 班次3 + 休息3 List<ScheduleRule> scheduleRuleList = new ArrayList<>(); for (int i = 0; i < shiftTypeCount; i++) { // 取 days / shiftTypeCount 向下取整 int workDays = workDaysInRange / shiftTypeCount; int restDays = scheduleRangeDays / 2 - workDays; if (i == shiftTypeCount - 1) { // 改为 取 余数 workDays = workDaysInRange - scheduleRuleList.stream() .filter(item -> item.getShiftType()!=ShiftType.REST) .mapToInt(ScheduleRule::getDays).sum(); restDays = scheduleRangeDays / 2 - workDays; } // 处理 scheduleRuleMap.get(i * 2 + 1).setDays(workDays); scheduleRuleMap.get(i * 2 + 2).setDays(restDays); scheduleRuleList.add(scheduleRuleMap.get(i * 2 + 1)); scheduleRuleList.add(scheduleRuleMap.get(i * 2 + 2)); } // 排班计划结果 scheduleRuleList.forEach(item -> System.out.println(item.toString())); // 人员分组 最好是事先完成初始化 Map<Integer, EmployeeGroup> employeeGroupMap = new HashMap<>(); employeeGroupMap.put(1, new EmployeeGroup(1)); employeeGroupMap.put(2, new EmployeeGroup(2)); employeeGroupMap.put(3, new EmployeeGroup(3)); Map<Integer, Employee> employeeMap = new HashMap<>(); employees.stream().filter(p-> p.getPosition().equals(position)) .forEach(employee -> employeeMap.put((employeeMap.size() + 1), employee)); employeeMap.keySet().forEach(index -> { int t = index % employeeGroupMap.size() + 1; employeeGroupMap.get(t).getEmployeeInGroup().add(employeeMap.get(index)); }); employeeGroupMap.forEach( (integer, employeeGroup) -> employeeGroup.getEmployeeInGroup().forEach( item -> System.out.println(employeeGroup.getGroup() + " : " +item.toString()) ) ); // 排班验证 LocalDate startDate = LocalDate.of(2025,1, 1); int fullScheduleDays = scheduleRangeDays * shiftTypeCount * (shiftTypeCount + 1); // 获取模板 LocalDate tmpStartDate = startDate; // 生成排班模版 14*6 = 84天 一个周期 LocalDate currentDate = LocalDate.now(); while (tmpStartDate.isBefore(currentDate)) { tmpStartDate = tmpStartDate.plusDays(fullScheduleDays); } tmpStartDate = tmpStartDate.plusDays(-fullScheduleDays); // 模拟排班规则 int totalDays = 0; int tmp = 0; String group = null; ShiftType shiftType = ShiftType.DAY; List<ScheduleTmpResult> scheduleTmpResultList = new ArrayList<>(); while (totalDays < fullScheduleDays) { tmp++; int index = tmp % scheduleRuleMap.size(); if (index == 0) { index = scheduleRuleMap.size(); } ScheduleRule scheduleRule = scheduleRuleMap.get(index); ScheduleTmpResult scheduleTmpResult = new ScheduleTmpResult(scheduleRule.getIndex(), scheduleRule.getDays()); if (null != group) { // 找到上一个 ScheduleTmpResult preScheduleTmpResult = scheduleTmpResultList.get(scheduleTmpResultList.size() - 1); Map<String, ShiftType> preGroupShiftTypeMap = preScheduleTmpResult.getGroupShiftTypeMap(); // 找到上一个REST 对应的 group name Set<String> groupNameSet = new HashSet<>(preGroupShiftTypeMap.keySet()); String preRestGroupName = null; for (String groupName: groupNameSet) { if (preGroupShiftTypeMap.get(groupName) == ShiftType.REST) { preRestGroupName = groupName; } } // 移出 groupNameSet.remove(preRestGroupName); group = preRestGroupName; // 找到再上一个对应的班次 ScheduleTmpResult prePreScheduleTmpResult = null; try { prePreScheduleTmpResult = scheduleTmpResultList.get(scheduleTmpResultList.size() - 2); } catch (Exception e) { } ShiftType nextShiftType = ShiftType.DAY; if (null != prePreScheduleTmpResult) { Map<String, ShiftType> groupShiftTypeMap = prePreScheduleTmpResult.getGroupShiftTypeMap(); ShiftType shiftType1 = groupShiftTypeMap.get(preRestGroupName); nextShiftType = shiftType1.getReverse(); } Map<String, ShiftType> groupShiftTypeMap = scheduleTmpResult.getGroupShiftTypeMap(); groupShiftTypeMap.put(preRestGroupName, nextShiftType); // 基于nextShiftType 寻找上一个 group ,让其进行休息 String preGroupNameB = null; for (String groupName: groupNameSet) { if (preGroupShiftTypeMap.get(groupName) == nextShiftType) { preGroupNameB = groupName; } } groupNameSet.remove(preGroupNameB); groupShiftTypeMap.put(preGroupNameB, ShiftType.REST); // 剩下的一组 不动 String otherGroupName = groupNameSet.iterator().next(); groupShiftTypeMap.put(otherGroupName, preGroupShiftTypeMap.get(otherGroupName)); scheduleTmpResult.setGroupShiftTypeMap(groupShiftTypeMap); } else { Map<String, ShiftType> groupShiftTypeMap = scheduleTmpResult.getGroupShiftTypeMap(); EmployeeGroup employeeGroupA = employeeGroupMap.get(1); groupShiftTypeMap.put(employeeGroupA.getGroup(), shiftType); EmployeeGroup employeeGroupB = employeeGroupMap.get(2); groupShiftTypeMap.put(employeeGroupB.getGroup(), shiftType.getNext()); EmployeeGroup employeeGroupC = employeeGroupMap.get(3); groupShiftTypeMap.put(employeeGroupC.getGroup(), shiftType.getNext().getNext()); scheduleTmpResult.setGroupShiftTypeMap(groupShiftTypeMap); group = employeeGroupC.getGroup(); } scheduleTmpResultList.add(scheduleTmpResult); totalDays = totalDays + scheduleRule.getDays(); } scheduleTmpResultList.forEach(System.out::println); // 将List分成各个组 Map<String, List<ScheduleResult>> scheduleResultMap = new HashMap<>(); int index = 0; for (ScheduleTmpResult item : scheduleTmpResultList) { index = index + 1; for (Map.Entry<String, ShiftType> entry : item.getGroupShiftTypeMap().entrySet()) { String gn = entry.getKey(); ShiftType st = entry.getValue(); List<ScheduleResult> orDefault = scheduleResultMap.getOrDefault(gn, new ArrayList<>()); ScheduleResult scheduleResult = new ScheduleResult(index, item.getDays(), st); orDefault.add(scheduleResult); scheduleResultMap.put(gn, orDefault); } } // 依次处理REST超过 3 的部分 int maxRestDays = restDaysInRange; int totalMaxRestDays = restDaysInRange * shiftTypeCount * (shiftTypeCount + 1); Set<String> keySet = scheduleResultMap.keySet(); while (maxRestDays > 1) { for (String gn : keySet) { List<ScheduleResult> scheduleResults = scheduleResultMap.get(gn); int nowTotalRestDays = scheduleResults.stream().filter(p -> p.getShiftType() == ShiftType.REST).mapToInt(ScheduleResult::getDays).sum(); for (int i = 0; i < scheduleResults.size(); i++) { if (nowTotalRestDays == totalMaxRestDays) { break; } ScheduleResult scheduleResult = scheduleResults.get(i); if (scheduleResult.getShiftType() == ShiftType.REST) { if (scheduleResult.getDays() > maxRestDays) { // 减少的数量 int needRemoveDays = scheduleResult.getDays() - maxRestDays; if (nowTotalRestDays - needRemoveDays < totalMaxRestDays) { needRemoveDays = totalMaxRestDays - nowTotalRestDays; } // 如果是最后一个 if (i == scheduleResults.size() - 1) { ScheduleResult preScheduleResult = scheduleResults.get(i - 1); preScheduleResult.setDays(preScheduleResult.getDays() + needRemoveDays); }else { ScheduleResult nxtScheduleResult = scheduleResults.get(i + 1); nxtScheduleResult.setDays(nxtScheduleResult.getDays() + needRemoveDays); } scheduleResult.setDays(scheduleResult.getDays() - needRemoveDays); nowTotalRestDays = nowTotalRestDays - needRemoveDays; } } } } // 减少1天,继续处理 maxRestDays--; } // 再次输出结果 for (String gn : keySet) { List<ScheduleResult> scheduleResults = scheduleResultMap.get(gn); int nowTotalRestDays = scheduleResults.stream().filter(p -> p.getShiftType() == ShiftType.REST).mapToInt(ScheduleResult::getDays).sum(); System.out.println(gn + " , " + nowTotalRestDays); for (ScheduleResult sr : scheduleResults) { System.out.println(sr); } } // 将结果输出为一个连续周期内的日期结果 List<ScheduleDateResult> scheduleDateResults = new ArrayList<>(); for (String gn : keySet) { LocalDate tmpDate = tmpStartDate; List<ScheduleResult> scheduleResults = scheduleResultMap.get(gn); // 输出两个full周期的内容,确保可以获取当前月或者下个月的内容 for (ScheduleResult sr : scheduleResults) { int days = sr.getDays(); for (int i = 0; i < days; i++) { ScheduleDateResult scheduleDateResult = new ScheduleDateResult(gn, tmpDate, sr.getShiftType()); scheduleDateResults.add(scheduleDateResult); tmpDate = tmpDate.plusDays(1); } } for (ScheduleResult sr : scheduleResults) { int days = sr.getDays(); for (int i = 0; i < days; i++) { ScheduleDateResult scheduleDateResult = new ScheduleDateResult(gn, tmpDate, sr.getShiftType()); scheduleDateResults.add(scheduleDateResult); tmpDate = tmpDate.plusDays(1); } } } // 输出全部数据 for (ScheduleDateResult scheduleDateResult : scheduleDateResults) { System.out.println(scheduleDateResult); } System.out.println("---------------------------------------------------------------------------"); // 截取需要的周期内的 ScheduleDateResult LocalDate start = LocalDate.of(2025,9,1).plusDays(-1); LocalDate end = LocalDate.of(2025,9,30).plusDays(1); List<ScheduleDateResult> newScheduleDateResults = scheduleDateResults.stream().filter(new Predicate<ScheduleDateResult>() { @Override public boolean test(ScheduleDateResult scheduleDateResult) { return scheduleDateResult.getDate().isBefore(end) && scheduleDateResult.getDate().isAfter(start); } }).collect(Collectors.toList()); // 最后结果输出 for (ScheduleDateResult scheduleDateResult : newScheduleDateResults) { System.out.println(scheduleDateResult); } } public static void main(String[] args) { new MyCstGenerator().init(); } }
输出结果
欢迎大家来到IT世界,在知识的湖畔探索吧!--------------------------------------------------------------------------- C组,2025-09-01,REST C组,2025-09-02,REST C组,2025-09-03,NIGHT C组,2025-09-04,NIGHT C组,2025-09-05,NIGHT C组,2025-09-06,NIGHT C组,2025-09-07,NIGHT C组,2025-09-08,NIGHT C组,2025-09-09,NIGHT C组,2025-09-10,REST C组,2025-09-11,REST C组,2025-09-12,REST C组,2025-09-13,DAY C组,2025-09-14,DAY C组,2025-09-15,DAY C组,2025-09-16,DAY C组,2025-09-17,DAY C组,2025-09-18,DAY C组,2025-09-19,DAY C组,2025-09-20,DAY C组,2025-09-21,DAY C组,2025-09-22,DAY C组,2025-09-23,REST C组,2025-09-24,NIGHT C组,2025-09-25,NIGHT C组,2025-09-26,NIGHT C组,2025-09-27,NIGHT C组,2025-09-28,NIGHT C组,2025-09-29,NIGHT C组,2025-09-30,NIGHT B组,2025-09-01,DAY B组,2025-09-02,DAY B组,2025-09-03,DAY B组,2025-09-04,DAY B组,2025-09-05,DAY B组,2025-09-06,DAY B组,2025-09-07,DAY B组,2025-09-08,DAY B组,2025-09-09,REST B组,2025-09-10,NIGHT B组,2025-09-11,NIGHT B组,2025-09-12,NIGHT B组,2025-09-13,NIGHT B组,2025-09-14,NIGHT B组,2025-09-15,NIGHT B组,2025-09-16,NIGHT B组,2025-09-17,REST B组,2025-09-18,REST B组,2025-09-19,REST B组,2025-09-20,DAY B组,2025-09-21,DAY B组,2025-09-22,DAY B组,2025-09-23,DAY B组,2025-09-24,DAY B组,2025-09-25,DAY B组,2025-09-26,DAY B组,2025-09-27,DAY B组,2025-09-28,DAY B组,2025-09-29,REST B组,2025-09-30,REST A组,2025-09-01,NIGHT A组,2025-09-02,NIGHT A组,2025-09-03,REST A组,2025-09-04,REST A组,2025-09-05,REST A组,2025-09-06,DAY A组,2025-09-07,DAY A组,2025-09-08,DAY A组,2025-09-09,DAY A组,2025-09-10,DAY A组,2025-09-11,DAY A组,2025-09-12,DAY A组,2025-09-13,DAY A组,2025-09-14,DAY A组,2025-09-15,REST A组,2025-09-16,REST A组,2025-09-17,NIGHT A组,2025-09-18,NIGHT A组,2025-09-19,NIGHT A组,2025-09-20,NIGHT A组,2025-09-21,NIGHT A组,2025-09-22,NIGHT A组,2025-09-23,NIGHT A组,2025-09-24,REST A组,2025-09-25,REST A组,2025-09-26,REST A组,2025-09-27,DAY A组,2025-09-28,DAY A组,2025-09-29,DAY A组,2025-09-30,DAY
输出结果转Excel
转Excel显示
欢迎大家来到IT世界,在知识的湖畔探索吧!
元宝给出的思路
关键约束分析
排班策略设计
方案验证
虽然,元宝给出的代码无法直接执行,但是也是给出了可用的设计方案思路,最终帮助作者君解决了问题。
如果你也有类似的自动排班想法,欢迎评论区留言或者私信沟通~
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/143387.html