EVA_duty_arrange_tool/solve.py

104 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

from ortools.linear_solver import pywraplp
def solve_program(preference_mat:list,
want_num_array:list,
is_new_array:list,
is_tech_array:list,
is_hr_array:list,
num_min=None,
num_max=None,
num_tech_min=None,
num_tech_max=None,
num_old_min=None,
num_old_max=None,
num_hr_min=None,
num_hr_max=None,
num_new_min=None,
num_new_max=None
):
is_old_array = [not is_new for is_new in is_new_array]
# 使用 SCIP 求解器求解组合优化问题
solver = pywraplp.Solver.CreateSolver("SCIP")
if not solver:
return
N = len(preference_mat) # 学生人数
M = len(preference_mat[0]) # 班次数
avg_num = sum(want_num_array) / M
print(f"平均人数:{avg_num}")
# 创建决策变量variables[i][j] 表示第i个学生是否选择第j个班次
variables = [[solver.IntVar(0.0, 1.0, f"choice_{i}_{j}")
for j in range(M)] for i in range(N)]
# 创建辅助变量用于优化目标(均衡班次人数)
aux_vars = [solver.NumVar(0.0, solver.infinity(), f"aux_{j}")
for j in range(M)]
print("Number of variables =", solver.NumVariables())
# 约束:每个同学意愿一定要满足
for i in range(N):
for j in range(M):
solver.Add(variables[i][j] <= preference_mat[i][j])
# 约束:辅助变量用于计算与平均人数的偏差(绝对值)
for j in range(M):
actual_num = sum(variables[i][j] for i in range(N))
solver.Add(aux_vars[j] >= actual_num - avg_num)
solver.Add(aux_vars[j] >= avg_num - actual_num)
# 约束:满足每位同学的意愿班次数
for i in range(N):
total_shifts = sum(variables[i])
if want_num_array[i] == 3:
solver.Add(total_shifts >= 2)
solver.Add(total_shifts <= 3)
else:
solver.Add(total_shifts == want_num_array[i])
# 添加班次人数约束的辅助函数
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:
solver.Add(shift_count >= min_val)
if max_val is not None:
solver.Add(shift_count <= max_val)
# 约束:每个班次的总人数
add_shift_constraint([1] * N, num_min, num_max)
# 约束:每班次电脑或电器的老人数量
tech_old_array = [is_old_array[i] * is_tech_array[i] for i in range(N)]
add_shift_constraint(tech_old_array, num_tech_min, num_tech_max)
# 约束:每班次老人数量
add_shift_constraint(is_old_array, num_old_min, num_old_max)
# 约束:每班次人资部小朋友数量
add_shift_constraint(is_hr_array, num_hr_min, num_hr_max)
# 约束:每班次小朋友数量
add_shift_constraint(is_new_array, num_new_min, num_new_max)
# 优化目标:最小化各班次人数与平均人数的偏差总和
solver.Minimize(sum(aux_vars))
# 求解
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
print("Optimal solution found:")
variables_return = [[variables[i][j].solution_value() for j in range(M)]
for i in range(N)]
aux_vars_return = [aux_vars[j].solution_value() for j in range(M)]
print(f"Optimized objective value: {solver.Objective().Value()}")
print(aux_vars_return)
return variables_return
else:
print("No solution found.")
return None