在前几天中,为了想出一个安排考场的算法,我是抓破了头,好不容易想到一个,却有两个不合适的地方:
1、算法中有bug,在前两天的那个算法中,先确定了一门课程,假设为课程A,然后查找所有与课程A不冲突的课程,假设有课程B和课程C与课程A不冲突,然后就将课程B、课程C与课程A放在同一时间考试。在这种方法里,我忽略了课程B和课程C是否有冲突的情况。
2、考试场次过多,131门课程需要106个场次的考试,一天考5场的话,需要22天才能考完,这明显不合事宜。
因此,那个算法可以说是一个完全失败的算法。
上网查了一下,无论是百度还是谷歌,都没有找到一个可行的、现成的算法,不过倒都提供了一个思路:顶点着色法。
什么叫顶点着色法?也就是说,将所有课程(如课程A、B、C、D)看成是一个个圆点,如果有一个学生同时选择了两门课程,假设选择了课程A和课程B,那么就在圆点A和圆点B之间划上一条联接线。如下图所示:
在上图中,课程A和课程B、课程E、课程F中间有连线,所以课程A是不能和课程B、课程E、课程F同时考试,而课程A和课程C、课程D、课程G、课程H之间都没有连线,那么课程A则可以和课程C、课程D、课程G、课程H是的一门或多门同时考。为什么说只能和课程C、课程D、课程G、课程H中的一门或多门同时考呢?我们再来看一下上面的图,课程C和课程D之间有连线,所以,课程A、课程C和课程D,这三门是不能同时考的。如果转换成顶点着色的问题,可以这么看,先将顶点A(即课程A)涂上一种颜色,假设为红色,那么顶点B、顶点E和顶点F就不能涂成红色。而顶点C、顶点D、顶点G、顶点H中有一个或多个可以涂成红色,因为它们和顶点A之间都没有连线。但是顶点C和顶点D不能同时为红色,因为它们之间有连线。
这样,选课问题就可以转换成顶点着色问题,即使将上图中所有顶点都涂满颜色,要求有两个:
1、中间有连线的两个顶点不能为同一种颜色。
2、要求使用最少的颜色涂满所有顶点。
确定了这种思想之后,又上谷歌下百度查询一翻,也看到了不少解决方法,什么回溯算法啊、蚂蚁算法啊,甚至还有DNA算法!看得我头都晕了,一个字:看不懂!对不起,晕了,是三个字。
看来求人不如求己了,于是,我决定,还是自己开动脑筋想吧。
一开始,我就钻进了顶点着色算法里去了。后来发现,这个算法不简单,不同的起点(即从不同的顶点入手)、不同的路径(即沿着不同的连线查询到不能着相同颜色的顶点),所得到的结果都不相同。我也没有办法将所有可能的路径都走一遍,然后再去判断哪条路径最短。更何况,还有一个考场最多可容纳考试人数的约束呢。
钻了很久,在我都想要放弃的时候,突然想到,为什么一定要以课程为考虑方向呢?为什么不能以人为考虑方向呢?科技都以人为本了,安排考场同样也应该以人为本才对嘛。
以人为本的考虑方法如下所示:
1、选出选课数最多的学生,很明显,该学生的所有考试是不能在同一时间进行的。所以,可以按次序安排这几门课程。以上图为例,假设学生A选择了课程A、课程E和课程F,那么,就可以将课程A安排在第1场次考(红色),课程E安排在第2场次考(蓝色),课程F安排在第3场次考(黄色),如下图所示。
2、然后找出1门与课程A不冲突的课程,也安排在第1场次考,如课程C、D、G、H。那到底是安排哪门课程在第1场次考呢?这个,我无法肯定,因为选择课程C还是课程D,有可能最后的结果会差别很大。但我考虑了一个,应该选选课人数最多的那门课程。假设课程C有100人选修,课程D有30人选修,那么就选择课程C,因为选课人数越多的课程,和其它课程的冲突的可能性也就越大,既然在这里没冲突了,那么就优先安排这门课程吧。如下图所示,课程C也使用红色填涂,这就说明,课程A和课程C可以同时进行考试。
3、然后,我们应该继续找和课程A、课程C都没有连线的顶点。在上图中我们可以看到,课程H和课程A、课程C都没有连线,那么课程H也可以放在第1场次考试。如下图所示。
4、查看是否还有与A、C、H节点都没有连线的节点。在上图中我们可以看出,已经不存在这样的节点了。(当次循环结束)
5、进入下一个循环,也就是查看第2场次考试的课程,前面我们已经将课程E安排在第2场次考,那么我们现在要看一下和节点E没有连线的节点。如上图所示,课程B、D、E和课程E都没有节点。先安排冲突最少的节点,也就是连线最少的节点——课程B,如下图所示。
6、再看和节点B、E都没有连线的节点,也就是节点D,那就说明,课程D可以在第2场次考。如下图所示:
7、最后,课程G和课程F正好没有冲突可以安排在第3场次中考。如下图所示。
在上例中,所有课程正好都已经安排了。但是,在现实中,会不有这么巧的事,所有课程都正好安排完,如果顶点G和顶点F之间有连线,那么课程G就只能安排在下一个考试场次中了,如下图所示。
经过以上几个步骤,我们以一个学生的所有选课(假设他选了N门课程)为基础,安排了N个场次的考试,那么,剩下的课程我们又要怎么做呢?这个时候,我们就不能再选择一个选课最多的学生,再根据他的选课情况来安排考场了。因为这个学生所选的课程,很有可能已经安排过了。
这个时候,我们可以用删除法来做,先将所有已经安排的课程删除,如上图中可以将除课程G之外的所有课程删除。然后,我们在学生的选课表中,将已经安排过的选课删除。这样,我们可以得到另一个顶点图和学生选课表,当然,这个顶点图和学生选课表是上一个顶点图和学生选课表的子集。由于没有了已安排的课程的干扰,我们可以将上面的步骤再循环地操作一次,安排其余的课程。
这样,一直循环下去,最后得到一个完整的考场安排表。
具体的SQL代码如下所示:
使用以上方法,成功的为13756人次、131门课程安排了考场,考试场次为22。
虽然以上方法不是最佳的,但是,这是可行的。
原创不容易,转载请注明出处。http://blog.csdn.net/smallfools/archive/2009/12/10/4977414.aspx
相关文章: