实验一:有约束的极值求解
实验目的
(1)通过排课问题理解非线性规划问题;
(2)熟悉有约束的极值求解方法;
(3)了解排课算法优化算法;
(4)熟悉list,dataFrame等数据结构
(5)养成高质量代码编写习惯。
实验要求:
(1)编码规范
(2)代码高效
(3)注释充分,程序可读性好
(4)程序无bug
(5)方法接口规范定义
实验内容
根据以下约束和排班原则进行排课算法设计
(1)同一个任课教师在一个教学时间段只能进行一门课程教学
(2)同一个班级在一个教学时间段只能进行一门课程教学
(3)同一个教室在一个教学时间段只能进行一门课程教学
(4)排课教室必须满足学生人数要求
(5)一个教师每天不能超过6节课
(6)每个学生班级每天不能超过8节课
(7)每个教学班同一门课程每天不能超过2节课
(8)总共不能超过10教室
实验步骤
1.算法设计
1.1数据结构设计
import pandas as pd
from pandas import DataFrame
import numpy as np
import random
file_name = '软件工程教学任务列表.xls'
pd.set_option('display.max_columns', 500)
# 开课任务
assign_info = pd.read_excel(file_name, sheet_name='教学任务', header=0)
# 教室信息
classroom_info = pd.read_excel(file_name, sheet_name='教室信息', header=0)
# 时间:
course_time_day = ['8:30~9:15', '9:20~10:05', '10:25~11:10', '11:15~12:00', '14:00~14:45', '14:50~15:35', '15:55~16:40','16:45~17:30']
# 星期
week = ['周一', '周二', '周三', '周四', '周五']
# 老师:名字,课程,课程表
class Teacher():
def __init__(self, name):
self.name = name
self.courseInfos = []
self.table = DataFrame('', index=course_time_day, columns=week)
def add_course_info(self, courseInfo):
self.courseInfos.append(courseInfo)
# 学生:数量
class StudentGroup(Teacher):
student_num = 0
pass
# 教室:编号,课程信息,容纳人数,课程表
class Classroom():
def __init__(self, roomId, room_set_num):
self.roomId = roomId
self.courseInfos = []
self.room_set_num = room_set_num
self.table = DataFrame('', index=course_time_day, columns=week)
def add_course_info(self, courseInfo):
self.courseInfos.append(courseInfo)
1.2 算法流程设计
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xzYV9qyk-1681868985728)(流程图1.png)]
1.3 功能模块设计
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gu6NgFBf-1681868985729)(功能模块图1.png)]
2.数据与处理
对教学任务信息,教室信息,教师信息,教学班级信息进行处理,组织排课算法需要的各数据和排课结果表,并对相关变量进行初始化
# -*- coding: utf-8 -*-
# 行
index_row = assign_info.index.tolist()
# 列
index_col = assign_info.columns.tolist()
# 教学班列表
name_group = list(set(assign_info['教学班名称'].values))
# 教师列表
name_teacher = list(set(assign_info['授课教师'].values))
# 教室列表
name_classroom=list(set(classroom_info['名称'].values))
# 教师列表
teachers = []
for name in name_teacher:
teacher = Teacher(name)
for index in index_row:
if assign_info.loc[index, '授课教师'] == name:
course_info = {
'name_group': assign_info.loc[index, '教学班名称'],
'name_course': assign_info.loc[index, '课程名称'],
'course_time_day': None,
'course_time_week': None,
'classroom': None,
}
teacher.add_course_info(course_info)
teachers.append(teacher)
# 学生班级列表
student_groups = []
for name in name_group: # 班级名
group = StudentGroup(name)
for index in index_row:
if assign_info.loc[index, '教学班名称'] == name:
course_info = {
'name_teacher': assign_info.loc[index, '授课教师'],
'name_course': assign_info.loc[index, '课程名称'],
'study_time_course': assign_info.loc[index, '周课时'],
'course_time_day': None,
'course_time_week': None,
'classroom': None,
}
group.student_num = assign_info.loc[index, '人数上限']
group.add_course_info(course_info)
student_groups.append(group)
# 教室列表
classrooms=[]
for roomName in name_classroom:
for index in classroom_info.index.tolist():
if classroom_info.loc[index,'名称']==roomName:
roomId=classroom_info.loc[index,'序号']
room_set_num=classroom_info.loc[index,'容量']
classroom=Classroom(roomId,room_set_num)
classrooms.append(classroom)
3.算法实现
按照每天最短教学时间及日课时差最小原则进行排课
# 排课
# 遍历任务列表
for i in index_row:
task = assign_info.loc[int(i), :]
course_name = task['课程名称']
# 遍历班级列表找到这个班级
for student_group in student_groups:
if student_group.name != task['教学班名称']:
continue
else:
table_g = student_group.table
w = table_g.columns.tolist()
random.shuffle(w)
for index_col_table in w:
for index_row_table in table_g.index.tolist():
# 判断班级当天课是否超过8节 且同样的课是否超过两节
student_daily_course_num = 0
# 用于判断同样的课是否超过两节
student_daily_course_info = {}
# 遍历学生当天第1节课-第10节课,将课表信息存储下来
for row in table_g.index:
if table_g.loc[row, index_col_table] == '':
continue
else:
course_info = table_g.loc[row, index_col_table]
if course_info in student_daily_course_info.keys():
student_daily_course_info[course_info] += 1
else:
student_daily_course_info[course_info] = 1
student_daily_course_num += 1
# 判断当天是否超过两节
isFull = False
course_num = 0
for key in student_daily_course_info.keys():
if course_name in key:
course_num += student_daily_course_info[key]
if course_num >= 2:
isFull = True
break
else:
continue
# 判断一天是否超过8节
if student_daily_course_num >= 8 or isFull:
break
else:
# 判断当前时间段是否有课
# 有课
if table_g.loc[index_row_table, index_col_table] != '':
continue
# 没课
else:
# 判断学时是否以及排完
course_info_num = 0
course_index = 0
for course_info_s in student_group.courseInfos:
if course_info_s['name_course'] != course_name:
continue
else:
course_index = student_group.courseInfos.index(course_info_s)
course_info_num = course_info_s['study_time_course']
break
if course_info_num <= 0:
break
else:
# 学生可以排课,遍历老师列表,找到老师
for teacher in teachers:
if teacher.name is not task['授课教师']:
continue
else:
# 提取老师的课程表
table_t = teacher.table
teacher_daily_course_num = 0
for row in table_t.index:
if table_t.loc[row, index_col_table]:
teacher_daily_course_num += 1
if teacher_daily_course_num >= 3:
break
else:
# 判断这节课老师是否有课,若没有则可以排课
if table_t.loc[index_row_table, index_col_table] != '': # 有课
break
else:
# 遍历教室,看看哪间教室可以用
random.shuffle(classrooms)
for classroom in classrooms:
table_r = classroom.table
if table_r.loc[
index_row_table, index_col_table] != '' or classroom.room_set_num < student_group.student_num:
continue
else:
# 都符合要求可以排课!
# 学生课表 加课
table_g.loc[
index_row_table, index_col_table] = course_name + '/' + teacher.name + '/' + str(
classroom_info['名称'][course_index])
# 周学时减1
student_group.courseInfos[course_index][
'study_time_course'] -= 1
# 老师课表 加课
table_t.loc[
index_row_table, index_col_table] = course_name + '/' + student_group.name + ''
# 教室课表 加课
table_r.loc[
index_row_table, index_col_table] = course_name + '/' + student_group.name
break
break
4.算法优化(选做)
本部分为选做:(1)可以使用蚁群算法等对排课算法进行优化,得到更优的排课方案;
(2)合理设计算法模块,使程序支持多种排课原则,比如按最短教学时间优先,(2)课程任务分布均匀优先(3)教师要求优先
#code
5.结果输出
(1)教师课表
(2)学生班级课表
(3)教室课表
#结果显示
clazz_name = (input("请输入班级名称:"))
print(clazz_name,":")
for clazz in student_groups:
if clazz.name == clazz_name:
display(clazz.table)
teacher_name = (input("请输入老师名称:"))
print("老师:",teacher_name)
for teacher in teachers:
if teacher.name == teacher_name:
display(teacher.table)
classroom_name = (input("请输入教室名称:"))
print("教室:",classroom_name)
for c in range(15):
if str(classroom_info['名称'][c]) == classroom_name:
display(classroom.table)
班级:大数据(本)20-1 :
周一 | 周二 | 周三 | 周四 | 周五 | |
---|---|---|---|---|---|
8:30~9:15 | 数据仓库与数据挖掘/教师2/10209 | 应用统计学/教师1/10207 | 数据仓库与数据挖掘/教师2/10209 | 应用统计学/教师1/10207 | |
9:20~10:05 | 数据仓库与数据挖掘/教师2/10209 | 应用统计学/教师1/10207 | 数据仓库与数据挖掘/教师2/10209 | 操作系统原理/教师5/10515 | |
10:25~11:10 | 数据可视化分析/教师4/10407 | 数据采集与网络爬虫/教师3/10210 | 操作系统原理/教师5/10515 | ||
11:15~12:00 | 数据可视化分析/教师4/10407 | 数据采集与网络爬虫/教师3/10210 | |||
14:00~14:45 | 数据可视化分析/教师4/10407 | ||||
14:50~15:35 | 数据可视化分析/教师4/10407 | ||||
15:55~16:40 | 操作系统原理/教师5/10515 | ||||
16:45~17:30 |
老师: 教师1
周一 | 周二 | 周三 | 周四 | 周五 | |
---|---|---|---|---|---|
8:30~9:15 | 应用统计学/班级:大数据(本)20-1 | 应用统计学/班级:大数据(本)20-1 | |||
9:20~10:05 | 应用统计学/班级:大数据(本)20-1 | ||||
10:25~11:10 | Linux程序设计/班级:软件(本)19-34 | ||||
11:15~12:00 | Linux程序设计/班级:软件(本)19-34 | ||||
14:00~14:45 | Linux程序设计/班级:软件(本)19-34 | ||||
14:50~15:35 | |||||
15:55~16:40 | |||||
16:45~17:30 |
教室: 10207
周一 | 周二 | 周三 | 周四 | 周五 | |
---|---|---|---|---|---|
8:30~9:15 | 面向对象程序设计/班级:软件(本)21-34 | ||||
9:20~10:05 | |||||
10:25~11:10 | C语言程序设计应用/班级:软件(本)21-34 | ||||
11:15~12:00 | |||||
14:00~14:45 | |||||
14:50~15:35 | |||||
15:55~16:40 | |||||
16:45~17:30 |
实验总结
- 知识总结:
- set() 函数创建一个无序不重复元素集
- for循环遍历列表
- loc函数定位行列
- random.shuffle将列表中的元素打乱顺序实现随机性,也可以使用data.reset_index(drop=True)
- 实验总结:
- 因为学校排课的不合理,我们之前并没有具体从零学习过Python知识,对于Python很多基础知识都不太了解
- 在学习数据分析时有接触过pandas库,在此次实验中加深了理解,并且在网上学习了dataframe的常用函数方法
- 对有约束的极值求解算法有了初步掌握
- 能力有限,没有实现算法优化
- 代码量比较大,根据参考代码慢慢理清了思维逻辑
实验总结
- 知识总结:
- set() 函数创建一个无序不重复元素集
- for循环遍历列表
- loc函数定位行列
- random.shuffle将列表中的元素打乱顺序实现随机性,也可以使用data.reset_index(drop=True)
- 实验总结:
- 因为学校排课的不合理,我们之前并没有具体从零学习过Python知识,对于Python很多基础知识都不太了解
- 在学习数据分析时有接触过pandas库,在此次实验中加深了理解,并且在网上学习了dataframe的常用函数方法
- 对有约束的极值求解算法有了初步掌握
- 能力有限,没有实现算法优化
- 代码量比较大,根据参考代码慢慢理清了思维逻辑