我目前正在开发一个网站,让我们大学的学生可以根据他们想要上的课程自动生成有效的课程表。
在着手处理网站本身之前,我决定先解决如何高效地安排课程的问题。
需要澄清几点:
1. 我们大学(我认为其他大学也是如此)的每门课程都由一个或多个章节组成。因此,例如,微积分I目前有4个可用章节。这意味着,根据章节数量以及课程是否有实验室,这会极大地影响排课过程。
2. 我们大学使用科目缩写和课程代码的组合来表示课程。例如,在微积分I的情况下:MATH 1110。
3. CRN是唯一标识章节的代码。
4. 我所就读的大学没有混合校区,男女学生(几乎)在不同的校区学习。我的意思是,校园被分成两个部分。
5. datetimes和timeranges字典旨在减少对datetime.datetime.strptime()的调用,后者是真正的瓶颈。
我的第一次尝试是使用循环算法,直到找到30个时间表为止。通过从输入课程中随机选择一个部分,然后尝试将其他课程的部分放置到该部分中来创建时间表。如果不是所有课程都适合时间表,即存在冲突,则放弃该时间表并继续循环。
显然,上述解决方案存在缺陷。算法运行时间太长,并且过于依赖随机性。
第二个算法与旧算法完全相反。首先,它使用itertools.product()生成所有可能的时间表组合集合。然后,通过交叉检查无效的时间表来迭代时间表。为了确保各种部分,验证之前会对时间表组合进行洗牌(random.shuffle())。同样,涉及了一些随机性。
经过一些优化,我能够使调度程序在平均包含5门课程的时间表下运行不到1秒钟。这很好,但一旦你开始添加更多课程,问题就开始了。
举个例子,当我提供一定的输入集时,可能的组合数量如此之大,以至于itertools.product()在合理的时间内无法终止,并且在此过程中消耗了1GB的RAM。
显然,如果我要将这个变成一个服务,我需要一个更快、更有效的算法。在网上和IRC上出现了两种算法:动态规划和遗传算法。
动态规划无法应用于此问题,因为如果我正确理解概念,它涉及将问题分解为较小的部分,分别解决这些部分,然后将这些部分的解决方案结合起来形成完整的解决方案。就我所见,这在这里不适用。
至于遗传算法,我不太理解它们,并且甚至无法想象如何在这种情况下应用它。我还知道GA对于极大的问题空间更有效,而这并不是那么大。
我有什么替代方案?是否有相对易于理解的方法来解决这个问题?或者我应该坚持现在的做法,希望不会有太多人在下学期选择8门课程?
我不是一个很好的作家,所以对于问题中的任何模糊之处,我很抱歉。请随时要求澄清,我会尽力帮助。
这是完整的代码。
在着手处理网站本身之前,我决定先解决如何高效地安排课程的问题。
需要澄清几点:
1. 我们大学(我认为其他大学也是如此)的每门课程都由一个或多个章节组成。因此,例如,微积分I目前有4个可用章节。这意味着,根据章节数量以及课程是否有实验室,这会极大地影响排课过程。
2. 我们大学使用科目缩写和课程代码的组合来表示课程。例如,在微积分I的情况下:MATH 1110。
3. CRN是唯一标识章节的代码。
4. 我所就读的大学没有混合校区,男女学生(几乎)在不同的校区学习。我的意思是,校园被分成两个部分。
5. datetimes和timeranges字典旨在减少对datetime.datetime.strptime()的调用,后者是真正的瓶颈。
我的第一次尝试是使用循环算法,直到找到30个时间表为止。通过从输入课程中随机选择一个部分,然后尝试将其他课程的部分放置到该部分中来创建时间表。如果不是所有课程都适合时间表,即存在冲突,则放弃该时间表并继续循环。
显然,上述解决方案存在缺陷。算法运行时间太长,并且过于依赖随机性。
第二个算法与旧算法完全相反。首先,它使用itertools.product()生成所有可能的时间表组合集合。然后,通过交叉检查无效的时间表来迭代时间表。为了确保各种部分,验证之前会对时间表组合进行洗牌(random.shuffle())。同样,涉及了一些随机性。
经过一些优化,我能够使调度程序在平均包含5门课程的时间表下运行不到1秒钟。这很好,但一旦你开始添加更多课程,问题就开始了。
举个例子,当我提供一定的输入集时,可能的组合数量如此之大,以至于itertools.product()在合理的时间内无法终止,并且在此过程中消耗了1GB的RAM。
显然,如果我要将这个变成一个服务,我需要一个更快、更有效的算法。在网上和IRC上出现了两种算法:动态规划和遗传算法。
动态规划无法应用于此问题,因为如果我正确理解概念,它涉及将问题分解为较小的部分,分别解决这些部分,然后将这些部分的解决方案结合起来形成完整的解决方案。就我所见,这在这里不适用。
至于遗传算法,我不太理解它们,并且甚至无法想象如何在这种情况下应用它。我还知道GA对于极大的问题空间更有效,而这并不是那么大。
我有什么替代方案?是否有相对易于理解的方法来解决这个问题?或者我应该坚持现在的做法,希望不会有太多人在下学期选择8门课程?
我不是一个很好的作家,所以对于问题中的任何模糊之处,我很抱歉。请随时要求澄清,我会尽力帮助。
这是完整的代码。
http://bpaste.net/show/ZY36uvAgcb1ujjUGKA1d/
注意:很抱歉使用了一个误导性的标签(调度)。
a|b
,如果c的计数不等于a + b的计数,则会发生冲突。使用这种冲突检测方法,6!(720)比较将几乎是瞬间完成的。(没有字符串操作,耶!) - kreativitea