基于Python/Gekko的乐队排程优化方案展示优化需求
乐队排程优化方案改进
问题需求
我所在的音乐学校举办学生乐队联合音乐节,需优化乐队演出排程,使有亲属关系的乐队演出时间间隔总和最小。目前已用Python/Gekko实现可行方案,但需做两项改进:
- 不再手动定义乐队数量
n,改为从用户输入的乐队列表自动统计; - 输出乐队名称而非ID(名称来自用户输入的乐队列表)。
后续还计划让目标函数支持用户输入,但暂不重点处理。以下是当前使用的代码:
from gekko import GEKKO import numpy as np m = GEKKO() #variables and constrains n = 10 #n of bands s = 10 #n of slots to play t = 25 #time in minutes one band spend on the stage x = m.Array(m.Var,(n,s),value=0,lb=0,ub=1,integer=True) #matrix of all bands(rows) x slots (columns) for j in range(s): m.Equation(m.sum([x[i,j] for i in range(n)])<=1) #since this is the decision I made it binary and sum<=1 to 1 slot can only be ocupied by one band for i in range(n): m.Equation(m.sum([x[i,j] for j in range(s)])==1) #since this is the decision I made it binary and sum=1 to 1 band only ocuppie one slot z = [k for k in range(1,s+1)] #array with slot index to use to calc time w = z*x*t #time the band will perform ;; used in objetive function #objective #in this exemple the band (1,4) and the band (1,5) have a relationship, and so do (3,2) and (1,9), so the objetive function bellow will try to minimize the sum of the time between bands that have relationship y = m.abs2(w.item(1, 4)-w.item(1, 5))+ m.abs2(w.item(3, 2)-w.item(1, 9)) m.Minimize(y) #solver m.options.SOLVER = 1 m.solve() #prints the schedule schedule = [(i+1, j+1) for i in range(n) for j in range(s) if x[i,j][0] == 1] schedule.sort(key=lambda x: x[1]) for band, slot in schedule: print(f"Band {band} is scheduled to play in slot {slot}")
修改后的代码
from gekko import GEKKO import numpy as np # 用户输入乐队列表,可直接替换为实际乐队名称 band_names = [ "摇滚少年团", "爵士风组合", "古典重奏组", "嘻哈小分队", "民谣唱作社", "电音实验团", "朋克突击队", "蓝调乐团", "流行唱跳团", "金属核乐队" ] m = GEKKO() # 自动从乐队列表获取乐队数量n n = len(band_names) s = 10 # 演出时段数量 t = 25 # 每个乐队演出时长(分钟) # 定义变量矩阵:乐队(行) x 时段(列),二进制变量 x = m.Array(m.Var, (n, s), value=0, lb=0, ub=1, integer=True) # 约束条件:每个时段最多一个乐队演出 for j in range(s): m.Equation(m.sum([x[i, j] for i in range(n)]) <= 1) # 约束条件:每个乐队必须演出一次 for i in range(n): m.Equation(m.sum([x[i, j] for j in range(s)]) == 1) # 计算每个乐队的演出时间点(时段序号*时长) z = np.array([k for k in range(1, s+1)]) w = z * x * t # 目标函数:最小化有亲属关系乐队的时间间隔总和(示例关系) # 注意:索引对应band_names列表的0下标(Python列表从0开始计数) y = m.abs2(w.item(0, 3) - w.item(0, 4)) + m.abs2(w.item(2, 1) - w.item(0, 8)) m.Minimize(y) # 求解器设置 m.options.SOLVER = 1 m.solve() # 生成并输出排程(按时段排序) schedule = [] for i in range(n): for j in range(s): if x[i, j][0] == 1: schedule.append((band_names[i], j+1)) schedule.sort(key=lambda item: item[1]) for band_name, slot in schedule: print(f"乐队 {band_name} 被安排在第 {slot} 个时段演出")
关键改动说明
- 自动获取乐队数量:通过
len(band_names)自动计算乐队总数n,无需手动硬编码; - 输出乐队名称:将原代码中依赖ID的逻辑替换为直接调用
band_names列表中的名称,排程输出时直接展示乐队名; - 索引适配:原代码目标函数使用1-based索引,修改后对应Python列表的0-based索引(比如原
w.item(1,4)对应新代码的w.item(0,3)); - 扩展性:
band_names列表可灵活替换,比如通过循环input()获取用户输入的乐队名称,或从文件读取批量数据。
内容的提问来源于stack exchange,提问作者Lucas Catharino
相关产品推荐
相关产品推荐

