排课算法小记

news2024/11/14 11:02:34

输出:
在这里插入图片描述

在配置文件(config.txt)中配置:老师,课程,专业班级,课时的信息,运行test.py自动生成对应班级课程表

eg:
专业1,四门课,每门课每周2课时,共8门课
专业2,四门课,每门课每周2课时
专业3,四门课,有三门课每周2课时,1门课每周1课时,每周共7门课
约束条件:

  • 同一个教室在同一个时间只能有一门课。
  • 同一个班级在同一个时间只能有一门课 。
  • 同一个教师在同一个时间只能有一门课。
  • 同一个班级在同一天不能有相同的课。

举个例子,增加一个班级305,一门3课时的课,一门2课时的课,老师和课程正常是一个老师开一门
运行一下,新的班级的五门课就加进去了

算法用的是遗传算法,先随机初始化,然后根据约束条件构建代价函数,不断迭代排序调整降低冲突量,冲突数为0,停止调整。
设置了500次的最大迭代次数,如果课程比较多,500次后冲突不为0,可以重新运行或者调大最大迭代次数。

课程超过了容量,就排不出来了

构思:
1.抽离约束条件

2.根据我们现有的课表分析,每天有8个课时,早上1234,下午5678,最小化每天时间为8份,前七份排课

3.设置成每天五节课也行,上午两节,下午三个班级的课程可以看做是三个独立的课程排课,也可当做每天三节课来排课

#班级:{301:1班,302:2班,303:3班}
#课程:{2001:诊断病理学,...}
#老师:{10001:A老师,...}
#课次:平均每周上几次课
#######
#老师 课程 班级 课次
10001 2001 301 2
10002 2002 301 2
10003 2003 301 2
10004 2004 301 2
10001 2001 302 2
10002 2002 302 2
10003 2003 302 2
10005 2005 302 2
10006 2006 303 1
10007 2007 303 2
import prettytable

from schedule import Schedule
from genetic import GeneticOptimize

import pandas as pd
# import openpyxl
def vis(schedule,name):
    """visualization Class Schedule.

    Arguments:
        schedule: List, Class Schedule
    """
    col_labels = ['week/slot', '1', '2', '3', '4', '5']
    table_vals = [[i + 1, '', '', '', '', ''] for i in range(6)]

    table = prettytable.PrettyTable(col_labels, hrules=prettytable.ALL)

    for s in schedule:
        weekDay = s.weekDay
        slot = s.slot
        text = ' 课程: {} \n 班级: {} \n 教室: {} \n 老师: {}'.format(s.courseId, s.classId, s.roomId, s.teacherId)
        table_vals[weekDay - 1][slot] = text

    for row in table_vals:
        table.add_row(row)

    pd_data=pd.DataFrame(table_vals,columns=['星期/时间','周一','周二','周三','周四','周五'])
    pd_data.to_csv(name,index=False,encoding='GBK')


if __name__ == '__main__':
    schedules = []
    vis_res = {}
    f=open('config.txt',encoding='utf-8')
    # 老师 课程 班级 课次
    for line in f:
        if line[:1]!='#':
            vis_res[int(line.split(' ')[2])]=list()
            for i in range(0,int(line.split(' ')[-1])):
                schedules.append(Schedule(int(line.split(' ')[1]), int(line.split(' ')[2]), int(line.split(' ')[0])))

    # optimization
    ga = GeneticOptimize(popsize=50, elite=10, maxiter=500)
    res = ga.evolution(schedules, 3)

    # visualization
    all_res=[]
    for r in res:
        all_res.append(r)
        vis_res[r.classId].append(r)
    vis(all_res,'总课表.csv')
    for key in vis_res.keys():
        vis(vis_res[key],'班级{}课表.csv'.format(key))

import copy
import numpy as np

from schedule import schedule_cost


class GeneticOptimize:
    """Genetic Algorithm.
    """

    def __init__(self, popsize=30, mutprob=0.3, elite=5, maxiter=100):
        # size of population
        self.popsize = popsize
        # prob of mutation
        self.mutprob = mutprob
        # number of elite
        self.elite = elite
        # iter times
        self.maxiter = maxiter

    def init_population(self, schedules, roomRange):
        """Init population

        Arguments:
            schedules: List, population of class schedules.
            roomRange: int, number of classrooms.
        """
        self.population = []

        for i in range(self.popsize):
            entity = []

            for s in schedules:
                s.random_init(roomRange)
                entity.append(copy.deepcopy(s))

            self.population.append(entity)

    def mutate(self, eiltePopulation, roomRange):
        """Mutation Operation

        Arguments:
            eiltePopulation: List, population of elite schedules.
            roomRange: int, number of classrooms.

        Returns:
            ep: List, population after mutation.
        """
        e = np.random.randint(0, self.elite, 1)[0]
        pos = np.random.randint(0, 2, 1)[0]

        ep = copy.deepcopy(eiltePopulation[e])

        for p in ep:
            pos = np.random.randint(0, 3, 1)[0]
            operation = np.random.rand()

            if pos == 0:
                p.roomId = self.addSub(p.roomId, operation, roomRange)
            if pos == 1:
                p.weekDay = self.addSub(p.weekDay, operation, 5)
            if pos == 2:
                p.slot = self.addSub(p.slot, operation, 5)

        return ep

    def addSub(self, value, op, valueRange):
        if op > 0.5:
            if value < valueRange:
                value += 1
            else:
                value -= 1
        else:
            if value - 1 > 0:
                value -= 1
            else:
                value += 1

        return value

    def crossover(self, eiltePopulation):
        """Crossover Operation

        Arguments:
            eiltePopulation: List, population of elite schedules.

        Returns:
            ep: List, population after crossover.
        """
        e1 = np.random.randint(0, self.elite, 1)[0]
        e2 = np.random.randint(0, self.elite, 1)[0]

        pos = np.random.randint(0, 2, 1)[0]

        ep1 = copy.deepcopy(eiltePopulation[e1])
        ep2 = eiltePopulation[e2]

        for p1, p2 in zip(ep1, ep2):
            if pos == 0:
                p1.weekDay = p2.weekDay
                p1.slot = p2.slot
            if pos == 1:
                p1.roomId = p2.roomId

        return ep1

    def evolution(self, schedules, roomRange):
        """evolution

        Arguments:
            schedules: class schedules for optimization.
            elite: int, number of best result.

        Returns:
            index of best result.
            best conflict score.
        """
        # Main loop .
        bestScore = 0
        bestSchedule = None

        self.init_population(schedules, roomRange)

        for i in range(self.maxiter):
            eliteIndex, bestScore = schedule_cost(self.population, self.elite)

            print('Iter: {} | conflict: {}'.format(i + 1, bestScore))

            if bestScore == 0:
                bestSchedule = self.population[eliteIndex[0]]
                break

            # Start with the pure winners
            newPopulation = [self.population[index] for index in eliteIndex]

            # Add mutated and bred forms of the winners
            while len(newPopulation) < self.popsize:
                if np.random.rand() < self.mutprob:
                    # Mutation
                    newp = self.mutate(newPopulation, roomRange)
                else:
                    # Crossover
                    newp = self.crossover(newPopulation)

                newPopulation.append(newp)

            self.population = newPopulation

        return bestSchedule

import numpy as np

class Schedule:
    """Class Schedule.
    """
    def __init__(self, courseId, classId, teacherId):
        """Init
        Arguments:
            courseId: int, unique course id.
            classId: int, unique class id.
            teacherId: int, unique teacher id.
        """
        self.courseId = courseId
        self.classId = classId
        self.teacherId = teacherId

        self.roomId = 0
        self.weekDay = 0
        self.slot = 0

    def random_init(self, roomRange):
        """random init.

        Arguments:
            roomSize: int, number of classrooms.
        """
        self.roomId = np.random.randint(1, roomRange + 1, 1)[0]
        self.weekDay = np.random.randint(1, 6, 1)[0]
        # self.slot = np.random.randint(1, 8, 1)[0]
        self.slot = np.random.randint(1, 6, 1)[0]

def schedule_cost(population, elite):
    """calculate conflict of class schedules.

    Arguments:
        population: List, population of class schedules.
        elite: int, number of best result.

    Returns:
        index of best result.
        best conflict score.
    """
    conflicts = []
    n = len(population[0])

    for p in population:
        conflict = 0
        for i in range(0, n - 1):
            for j in range(i + 1, n):
                # check course in same time and same room
                if p[i].roomId == p[j].roomId and p[i].weekDay == p[j].weekDay and p[i].slot == p[j].slot:
                    conflict += 1
                # check course for one class in same time
                if p[i].classId == p[j].classId and p[i].weekDay == p[j].weekDay and p[i].slot == p[j].slot:
                    conflict += 1
                # check course for one teacher in same time
                if p[i].teacherId == p[j].teacherId and p[i].weekDay == p[j].weekDay and p[i].slot == p[j].slot:
                    conflict += 1
                # check same course for one class in same day
                if p[i].classId == p[j].classId and p[i].courseId == p[j].courseId and p[i].weekDay == p[j].weekDay:
                    conflict += 1

        conflicts.append(conflict)

    index = np.array(conflicts).argsort()

    return index[: elite], conflicts[index[0]]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/73898.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springcloud(服务消费及熔断)

目录 1. 服务消费方式 1.1 RestTemplate1.2 feign2. 服务熔断&#xff08;降级&#xff09; 2.1 在微服务架构中服务熔断的必要性2.2 hystrix2.3 hystrix的使用 1. 服务消费方式 1.1 RestTemplate 传统情况下在java代码里访问restful服务&#xff0c;一般使用Apache的HttpClie…

[附源码]JAVA毕业设计田径运动会管理系统(系统+LW)

[附源码]JAVA毕业设计田径运动会管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技…

Vue项目实战 可视化 创建(vue2+Element ui)

Vue项目实战创建项目通过脚手架 创建项目 配置 vue 路由配置 element—ui 组件库配置 axios 库创建远程仓库初始化 git 远程仓库 将本地项目托管到 码云前端项目初始化步骤① 安装vue脚手架② 通过脚手架 创建项目③ 配置 vue 路由④ 配置 element—ui 组件库⑤ 配置 axios 库⑥…

基于小波变换的去噪,带GUI界面,可以设置小波变换层数

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 近年来&#xff0c;小波理论得到了非常迅速的发展&#xff0c;而且由于其具备良好的时频特性&#xff0c;因而实际应用也非常广泛。在去噪领域中&#xff0c;小波理论也同样受到了许多学者的重视…

关于我的Oracle Primavera P6/Unifier/Gateway离线帮助中心

目录 ​编辑 一、前序 二、路子 三、用途 四、最后 一、前序 经常到处飞&#xff0c;很多时候会又比较依赖于网页查看产品的帮助&#xff0c;而网页又比较依赖于网络 怎么办呢 有人提到通过官方提供的PDF&#xff0c;毕竟上面的内容和网页展现几乎完全一样&#xff0c;…

【ChatGPT】与ChatGPT聊天,了解世界杯的前世今生

文章目录&#x1f3c6; 前言&#x1f4ac; 什么是ChatGPT⚽ 与ChatGPT的快问快答&#x1f9e9; 总结&#x1f3c6; 前言 最近火爆全网的chatGPT&#xff0c;吸引一大批技术爱好者的疯狂围观。大家使用过后&#xff0c;纷纷发出惊叹&#xff0c;深陷其中&#xff0c;无法自拔。 …

数字信号处理用脉冲响应不变法和双线性变换法设计巴特沃斯滤波器MATLAB实现——实例

文章目录符号含义例题脉冲响应不变法双线性变换法画图完整代码符号含义 例题 脉冲响应不变法 clear close all clcfs1000;%采样频率 fc200;%通带截止频率 fr300;%阻带截止频率 T0.001; %采样周期%%%%%%%脉冲响应不变法 wp12*pi*fc;%通带截止频率 wr12*pi*fr;%阻带截止频率[N1,…

数据分享|用加性多元线性回归、随机森林、弹性网络模型预测鲍鱼年龄和可视化...

原文链接&#xff1a;http://tecdat.cn/?p24127鲍鱼是一种贝类&#xff0c;在世界许多地方都被视为美味佳肴&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。介绍相关视频养殖者通常会切开贝壳并通过显微镜计算环数来估计鲍鱼的年龄。因此&#xff0c;判断鲍鱼…

【QT开发笔记-基础篇】| 第五章 绘图QPainter | 5.3 初始化数据

本节对应的视频讲解&#xff1a;B_站_视_频 https://www.bilibili.com/video/BV1qd4y1s7xk 布局完成后&#xff0c;就可以修改控件的名称&#xff0c;以及添加初始化数据 1. 变量命名 先修改各控件显示的的名称&#xff0c;做到 “见名知义”&#xff0c;方便写代码 修改完…

C语言开发《推箱子游戏》,亲自手把手教会大家

【C语言经典算法100道实战题】适合具备C语言基础语法的同学学习&#xff0c;提高编写程序的逻辑思维能力和算法设计能力专门精心设计。100个经典的算法供大家练习及配套对应的录播视频。为我们今后学习其它的编程语言和软件开发打下坚实的基础&#xff0c;让你在编码道路上如鱼…

【手把手】教你玩转消息中间件之RabbitMQ

1、微服务下现存的各种问题 服务调用问题 当两个服务调用时&#xff0c;可以通过传统的HTTP方式&#xff0c;让服务A直接去调用服务B的接口&#xff0c;但是这种方式是同步的方式&#xff0c;虽然可以采用SpringBoot提供的Async注解实现异步调用&#xff0c;但是这种方式无法…

gsva gsea ssgsea gaochao 使用GSVA方法计算某基因集在各个样本的表现

傻傻分不清!GSEA & GSVA有啥差别?史上最全教程来了! - 知乎 (zhihu.com) 文章发表于2013年,GSVA: gene set variation analysis for microarray and RNA-Seq data 同样是broad 研究生出品,其在2005年PNAS发表的gsea已经高达1.4万的引用了,不过这个GSVA才不到300。 G…

【边缘检测】基于模糊算法的图像边缘检测附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步进步&#xff0c;matlab项目目标合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信息&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算…

实时数仓Flink生产环境部署+提交作业【步骤】

文章目录1、基础环境2、开发环境2.1、pom.xml2.2、log4j.properties2.3、测试用的代码2.3.1、Kafka工具2.3.3、Flink执行环境工具2.3.3、测试Flink读写Kafka2.3.4、测试FlinkSQL读写Kafka2.4、打包后上传到服务器3、生产环境3.1、Flink安装3.2、Flink on YARN下3种模式3.2.1、S…

Linux下POSIX信号量以及基于环形队列的生产消费模型

目录 一、POSIX信号量介绍 1. 信号量原理 2&#xff0c;初始化信号量 3,信号量销毁 4&#xff0c;信号量等待 5,发布信号量 二&#xff0c;基于环形队列的生产消费模型 1.基于单线程 2&#xff0c;测试&#xff1a; 3&#xff0c;基于多线程 4,测试 三&#xff0c;代…

故障转移,服务发现,负载均衡所运用的连接池

没错&#xff0c;说的就是连接池&#xff0c;玩互联网架构&#xff0c;连接池是必须要掌握的。 什么是连接池&#xff1f; 创建与管理连接缓冲池的技术&#xff0c;本质是资源复用&#xff0c;不用频繁创建与销毁连接&#xff0c;能提高性能。 画外音&#xff1a;数据库连接池…

Sentinel-2 L2A数据导入ENVI

Sentinel-2 L2A数据导入ENVI前言0 首先对SNAP进行设置1 用SNAP对Sentinel-2数据重采样2 在ENVI中打开重采样后的Sentinel-2数据3 其实不用重采样也行&#xff0c;ENVI可以直接打开解压后的Ssentinel-2文件&#xff0c;只需要将解压后的MTD_MSIL2A.xml拖进ENVI即可前言 Sentine…

揭秘倚天实例背后的硬核实力

2022云栖大会&#xff0c;阿里巴巴宣布自研CPU倚天710已大规模应用&#xff0c;阿里云未来两年20%的新增算力将使用自研CPU。11月15日&#xff0c;倚天710云实例上线并正式进入大规模应用阶段&#xff0c;现已应用于阿里巴巴集团核心业务&#xff0c;并服务科学研究、智能手机行…

[附源码]JAVA毕业设计天津城建大学校友录管理系统(系统+LW)

[附源码]JAVA毕业设计天津城建大学校友录管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。…

Nvidia力作:医学图像分割网络

来源&#xff1a;投稿 作者&#xff1a;梦飞翔 编辑&#xff1a;学姐 引自Unetr: Transformers for 3d medical image segmentation 1.序言 本文将以Nvidia团队最近提出的一种新的医学图像分割网络作为切入点&#xff0c;结合所用开源数据集&#xff0c;为各位同学提供一份从…