From 7bd2394d2c47678defc5637d3a02db0588ea37d7 Mon Sep 17 00:00:00 2001 From: Dawn1Ocean <1785590531@qq.com> Date: Sun, 26 Apr 2026 20:27:08 +0800 Subject: [PATCH] fix: bugs when available times less than duties wanted --- .DS_Store | Bin 0 -> 10244 bytes README.md | 7 ++-- main.py | 82 +++++++++++++++++++++++++++++++++++++-- solve.py | 8 ++-- utils.py | 20 +++++----- 使用手册.md | 23 ++++++++++- 问卷星结果_缺班样例.xlsx | Bin 0 -> 21155 bytes 7 files changed, 119 insertions(+), 21 deletions(-) create mode 100644 .DS_Store create mode 100644 问卷星结果_缺班样例.xlsx diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ba9c5ab5f9178c7f0742a70b8a54f418b7fc4c24 GIT binary patch literal 10244 zcmeHMYitx%6h3EK=&T*-P$blBuX@530XT%@`MZ&+bu|=ob+GqF~ z@H60Nz|Vl60Y3x(h78c0%`UlIP`~vv;Agd|3Ag*u>62lPfpZ-;_>bkYlR zalojce(Ptz&%o#mu)TXZ?bhQk2)hgR@9|dCP9;q{NfNB6ny9Fz+~5~CGYOKA0Rv3X ziX=}KNtS{}at^qKayWN9x#W;D=#6|TIcOS=8;M*%sibt$Z3aC3{}lux#JHfIPiw$?DDVesjRGpXE6K^nQ-uR?#1657E;| z+@_Ol7V(tCa`9Zu#S^%tT)8#a)!nmI+1_oWY%6B$(c@}`LqWAtcVk-5QZQX9+sq7D zPF$UuN|>pPnQ-++(`3TLt8h|j+cY=Yj^P@%)zj_jyWE_if>+&J9Xstdb7OH;%{cmI zoopFdy@f22sY*6l`yeypY|+yW(W+=f1Qs|kWoBqzbxr;9HPN-LZJW+ls8cHyW%`V+ ztl=0*Q}0PQDc#ZxtG9E=(A>VQlv&F)b{cv*5SWUKJFLWje!gslw z-I=8Ec*bydt5vcr#t6=>3drjF+ck2s&DNMjjlT&7=iV*L+Zew&ty3%5N^sF)Qb=?- zlpxQ|NL?VHIvxG=`Gu--&oVinYMo{xshb{a)oNm`@5+kEJ?8ZLk=_7354GG6>AJnZ8mzvkf@>ZuWk=EOX2z)t>4YJHXEb*DjTFr3nG|$GvbA!Pi zW~x!sbd7?ZJ?r+$U@X`vt6!0hYFJr=;7;E{pkA)ZA+0L9P&`(hHKY8A=QuDeC*V;w z!3JRgtbizVz)rB?033$b;5|4EXW$%MfJ<;0uD~_;6@G*3Sb_>x;vAfZHMj&LScj`{ zHLk(?a6NWlCvL$c_M?ddXrqh!@Cn?H2k!mIc@UdJ2KRB5&}Pns_+kd{ahsa|T39*`cCHcCBGQtFlZLcj%gp2SUq5LXb!^v2VDu%EcYjFjk`T<;rt+)Z(2-)4(gWGUB>e!2Y_!!~b z#ViitZrp6I(i%;gTzS{O}0miCff=+re_-cP(y8+tO|XHEYMP5v^Lb{P5xytKw}#;`WVuZL_X(B zmy$(;78g#TRViI0H-#@k2FV*69%C_(SGC-;0Wb@7*>VJ4&GRS#n<-0;&;o5lYstSc zmL&xmchERGWh+Bjb19?s5TSb+wM#jTLmjN-&ke+_gqG>m6; z)Y538R+p2{<64Ek?kmel9V{nb>nH51Oj%+`%u;s8KnIJh;5*11(`+F*KKAmzbQ#HK z$+AhKq@cg>dvNR(NVo6LR43POI!qd)F~LxjkJO46uf&FShMxGk_Z5iuEpI<`4MV{#DM;%))ru5<`E!r)vJ#M-KKL*z?Pu>9em{;5&8w%g=zH0Y3v1%Rq?` z3$ye8wd4Q)e`3abDL(^#2L6*7z|xjj3tI{0cG$&HNW=)!{V3h+VsgWRausTr2;=kP ucm9Uk%bQI9t)C|4&vu1-{(=KtgW4Dk2=?5xV)|NoEo|9=2h7wPc; literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 9371d2b..a49222f 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,9 @@ uv run pyinstaller --onefile --windowed --name=EVA_duty_arrange_tool --hidden-im - **目标5**:每一班各部门人数的平均程度 在本问题中,主要约束是: -1. 让每位同学每周的班次数符合意愿(特别地,选择3次的同学可以安排2-3次) +1. 让每位同学每周的班次数符合意愿(特别地,选择3次的同学可以安排2-3次;若某同学的可用班次数少于其期望值班次数,则自动降至可用数量) 2. 让每位同学只在自己有空的时间段值班 -3. 每班次的总人数在指定范围内 +3. 每班次的总人数在指定范围内(无人选择的班次豁免下限约束,视为无人值班) 4. 每班次技术部老人数量在指定范围内 5. 每班次老人总数在指定范围内 6. 每班次小朋友总数在指定范围内 @@ -165,4 +165,5 @@ OR-Tools 支持 `C++`、`Python`、`C#`、`Java` 等多种语言,并提供跨 ## 维护指南 - 如果你想更改 Excel 的读取、写入相关的功能,应该修改 `utils.py` 中的相关函数。 - 如果你想更改软件的前端界面,应该修改 `main.py` 中 `MyWidget` 这个类相关的代码。 -- 如果你想更换排班问题的建模方式、更换求解器、增减限制条件,应该修改 `solve.py` 中的相关代码。 \ No newline at end of file +- 如果你想更换排班问题的建模方式、更换求解器、增减限制条件,应该修改 `solve.py` 中的相关代码。 +- 如果你想更改异常数据(缺班、可用班次不足)的检测和处理逻辑,应该修改 `main.py` 中 `magic` 方法内对应的检查块,以及 `solve.py` 中 `solve_program` 的 `exempt_shifts` 参数相关逻辑。 \ No newline at end of file diff --git a/main.py b/main.py index 57150ae..7864521 100644 --- a/main.py +++ b/main.py @@ -41,8 +41,8 @@ class SolverThread(QtCore.QThread): finished_signal = QtCore.Signal(object, dict) # 发送求解结果 (vars, params) error_signal = QtCore.Signal(str) # 发送错误消息 - def __init__(self, preference_mat, depart_mat, want_num_array, is_new_array, - auto_mode, manual_params=None, parent=None): + def __init__(self, preference_mat, depart_mat, want_num_array, is_new_array, + auto_mode, manual_params=None, exempt_shifts=None, parent=None): super().__init__(parent) self.preference_mat = preference_mat self.depart_mat = depart_mat @@ -50,6 +50,7 @@ class SolverThread(QtCore.QThread): self.is_new_array = is_new_array self.auto_mode = auto_mode self.manual_params = manual_params or {} + self.exempt_shifts = exempt_shifts or [] def run(self): try: @@ -80,6 +81,7 @@ class SolverThread(QtCore.QThread): depart_mat=self.depart_mat, want_num_array=self.want_num_array, is_new_array=self.is_new_array, + exempt_shifts=self.exempt_shifts, **test_params ) if vars: @@ -102,6 +104,7 @@ class SolverThread(QtCore.QThread): want_num_array=self.want_num_array, depart_mat=self.depart_mat, is_new_array=self.is_new_array, + exempt_shifts=self.exempt_shifts, **self.manual_params ) final_params = self.manual_params @@ -303,6 +306,77 @@ class MyWidget(QtWidgets.QWidget): self.text_solve.append(f"\t平均每班人数:{all_sum/20}") self.text_solve.append(f"\t所有班次中最少拥有意愿数:{min_prefer}") + # 检查是否有班次没有任何同学选择 + CLASS_NAMES = [ + "周一第一班", "周一第二班", "周一第三班", + "周二第一班", "周二第二班", "周二第三班", + "周三第一班", "周三第二班", "周三第三班", + "周四第一班", "周四第二班", "周四第三班", + "周五第一班", "周五第二班", "周五第三班", + "周六第一班", "周六第二班", "周六第三班", + "周日第一班", "周日第二班" + ] + empty_classes = [ + j for j in range(class_num) + if sum(preference_mat[i][j] for i in range(len(preference_mat))) == 0 + ] + if empty_classes: + empty_names = [ + CLASS_NAMES[j] if j < len(CLASS_NAMES) else f"第{j+1}班" + for j in empty_classes + ] + warning_detail = "、".join(empty_names) + self.text_solve.append(f"警告:以下班次没有任何同学选择:{warning_detail}") + reply = QtWidgets.QMessageBox.question( + self, + "警告:存在无人选择的班次", + f"以下班次没有任何同学选择:\n\n{warning_detail}\n\n" + f"点击「确定」将这些班次视为无人值班并继续排班,\n" + f"点击「取消」放弃排班。", + QtWidgets.QMessageBox.StandardButton.Ok | QtWidgets.QMessageBox.StandardButton.Cancel, + QtWidgets.QMessageBox.StandardButton.Cancel + ) + if reply == QtWidgets.QMessageBox.StandardButton.Cancel: + self.text_solve.append("排班已取消。") + self.button_solve.setEnabled(True) + self.button_solve.setText("开始排班!") + return + self.text_solve.append(f"继续排班,以下班次将视为无人值班:{warning_detail}") + + # 检查是否有同学选择的可用班次少于期望值班次数 + want_num_adjusted = list(want_num_array) + infeasible_students = [] + for i in range(len(preference_mat)): + avail = sum(preference_mat[i][j] for j in range(class_num)) + want = want_num_array[i] + min_want = 2 if want == 3 else want + if avail < min_want: + infeasible_students.append((i, self.index_to_name_dict[i], avail, want)) + + if infeasible_students: + student_details = "\n".join( + f" {name}:期望 {want} 班,仅选了 {avail} 个可用班次" + for _, name, avail, want in infeasible_students + ) + self.text_solve.append(f"警告:以下同学的可用班次数少于期望值班次数:{', '.join(n for _, n, _, _ in infeasible_students)}") + reply = QtWidgets.QMessageBox.question( + self, + "警告:存在同学可用班次不足", + f"以下同学选择的可用班次数少于其期望值班次数:\n\n{student_details}\n\n" + f"点击「确定」按实际可用班次数安排他们并继续排班,\n" + f"点击「取消」放弃排班。", + QtWidgets.QMessageBox.StandardButton.Ok | QtWidgets.QMessageBox.StandardButton.Cancel, + QtWidgets.QMessageBox.StandardButton.Cancel + ) + if reply == QtWidgets.QMessageBox.StandardButton.Cancel: + self.text_solve.append("排班已取消。") + self.button_solve.setEnabled(True) + self.button_solve.setText("开始排班!") + return + for i, name, avail, want in infeasible_students: + want_num_adjusted[i] = avail + self.text_solve.append(f"调整:{name} 的期望班次由 {want} 调整为 {avail}") + def get_weight_value(key): text = self.weight_widgets[key].text() return float(text) if text else 0.0 @@ -326,8 +400,8 @@ class MyWidget(QtWidgets.QWidget): # 创建并启动求解线程 self.solver_thread = SolverThread( - preference_mat, depart_mat, want_num_array, is_new_array, - self._auto_mode, params, self + preference_mat, depart_mat, want_num_adjusted, is_new_array, + self._auto_mode, params, empty_classes, self ) # 连接信号 diff --git a/solve.py b/solve.py index 8640083..ee525e9 100644 --- a/solve.py +++ b/solve.py @@ -5,12 +5,14 @@ def solve_program(preference_mat:list, depart_mat:list, want_num_array:list, is_ num_tech_old_min=None, num_tech_old_max=None, num_old_min=None, num_old_max=None, num_new_min=None, num_new_max=None, - weights=[1.0, 1.0, 1.0, 0.5, 0.5] + weights=[1.0, 1.0, 1.0, 0.5, 0.5], + exempt_shifts=None ): is_old_array = [not is_new for is_new in is_new_array] is_tech_array = [depart_mat[i][0] == 1 or depart_mat[i][1] == 1 for i in range(len(depart_mat))] is_hr_array = [depart_mat[i][2] == 1 for i in range(len(depart_mat))] + exempt_set = set(exempt_shifts or []) # 使用 SCIP 求解器求解组合优化问题 solver = pywraplp.Solver.CreateSolver("SCIP") @@ -115,11 +117,11 @@ def solve_program(preference_mat:list, depart_mat:list, want_num_array:list, is_ else: solver.Add(total_shifts == want_num_array[i]) - # 添加约束的辅助函数 + # 添加约束的辅助函数(exempt_set 中的班次跳过下限约束) def add_shift_constraint(array, min_val, max_val): for j in range(M): shift_count = sum(variables[i][j] * array[i] for i in range(N)) - if min_val is not None: + if min_val is not None and j not in exempt_set: solver.Add(shift_count >= min_val) if max_val is not None: solver.Add(shift_count <= max_val) diff --git a/utils.py b/utils.py index 9f1278f..ed76676 100644 --- a/utils.py +++ b/utils.py @@ -91,15 +91,17 @@ def save_to_excel(variables, all_data, index_to_name_dict, file_path): hr_new_index.append(idx) # 选择值班组长(优先级:人资部小朋友 > 非技术部小朋友 > 小朋友 > 所有人) - if hr_new_index: - duty_monitor_index = choice(hr_new_index) - elif none_tech_new_index: - duty_monitor_index = choice(none_tech_new_index) - elif new_index: - duty_monitor_index = choice(new_index) - else: - duty_monitor_index = choice(all_index) - on_duty_list[duty_monitor_index]["duty_monitor"] = True + # 无人值班的班次跳过组长选择 + if all_index: + if hr_new_index: + duty_monitor_index = choice(hr_new_index) + elif none_tech_new_index: + duty_monitor_index = choice(none_tech_new_index) + elif new_index: + duty_monitor_index = choice(new_index) + else: + duty_monitor_index = choice(all_index) + on_duty_list[duty_monitor_index]["duty_monitor"] = True on_duty_list.sort(key=lambda x: x["department"]) all_result.append(on_duty_list) diff --git a/使用手册.md b/使用手册.md index 78706e1..1ef21b5 100644 --- a/使用手册.md +++ b/使用手册.md @@ -1,4 +1,4 @@ -# EVA 值班排班工具使用手册 - v2.0.0 +# EVA 值班排班工具使用手册 - v2.1.0 ## 前言 这是浙江大学学生E志者协会“排班工具软件”的使用手册,将简要地介绍该软件的使用方法和注意事项。请注意,这是面向使用者而非开发者的手册,如果想了解该工具的开发流程和所使用的技术,请移步至[此仓库](https://git.zjueva.net/happywind/EVA_duty_arrange_tool)的说明手册。 @@ -53,7 +53,7 @@ - 第 10 ~ 29 列,表示对于每个班次的意愿(1 代表有时间,0 代表没时间)。因为从周一第一班到周日第二班一共有 20 班,所以总共有 20 列。 - 第 30 列,表示愿意排几班,用一个数字表示。 - **我们提供了一个名为“问卷星结果_样例输入.xlsx”的文件,以作为正确输入格式的参考,以及一个名为“问卷星结果_较极端案例.xlsx”的文件,以作为程序运行的测试。** + **我们提供了一个名为”问卷星结果_样例输入.xlsx”的文件,以作为正确输入格式的参考,以及一个名为”问卷星结果_较极端案例.xlsx”和”问卷星结果_缺班样例.xlsx”的文件,以作为程序运行的测试。** **本软件可以自动处理同一名同学多次填写问卷的情况**,只要保证多次填写中“姓名”保持一致即可,软件将会自动选择最后一次填写的结果作为最终意愿。由于“姓名”是每位同学的唯一标识符,如果出现了某位同学“姓名”填错的情况,需要手动删除该姓名的记录。 @@ -95,3 +95,22 @@ 点击"开始排班!"按钮开始计算: - 输出结果以 Excel 表格形式保存,文件名为 `result_<当前时间戳>.xlsx` - **在输出结果中,组长会被标黄** + - **无人值班的班次在输出结果中对应格为空** + +## 异常数据处理 + +软件在排班前会自动对输入数据进行两项检查,遇到异常时会弹出对话框提示用户选择处理方式。 + +### 情况一:某班次无人选择 + +若某个(或某几个)班次没有任何同学选择,软件会弹出警告,列出所有无人选择的班次名称,并提供两个选项: + +- **确定**:将这些班次视为无人值班,继续进行其余班次的排班。输出结果中这些班次对应格为空。 +- **取消**:放弃本次排班,返回主界面。 + +### 情况二:某同学的可用班次数少于期望值班次数 + +若某位同学填写的期望值班次数多于其实际选择的可用班次数(例如希望值 2 班但只选了 1 个有空的时间段),软件会弹出警告,列出受影响的同学姓名及具体数据,并提供两个选项: + +- **确定**:自动将这些同学的期望值班次数调整为其实际可用班次数,继续排班。调整详情会在日志中显示。 +- **取消**:放弃本次排班,返回主界面,以便手动核查问卷数据。 diff --git a/问卷星结果_缺班样例.xlsx b/问卷星结果_缺班样例.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c5252649373cf52da2772dc4694f12e28778c3ed GIT binary patch literal 21155 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 D3tcv& literal 0 HcmV?d00001