您的位置:首页 > 其它

软件工程实践2017结对项目——第二次作业

2017-10-09 21:41 288 查看

成员

练斐弘 031502518

叶己峰 031502537

Github

传送门

问题描述

作业需求

编码实现一个部门与学生的智能匹配的程序。

提供输入包括:

20个部门

部门编号(唯一确定值),字符;

各部门需要学生数的要求的上限,单个,数值,在[10,15]内;

各部门的特点标签,多个(两个以上),字符;

各部门的常规活动时间段,多个(两个以上),字符。

300个学生

学生编号(唯一确定值),字符;

学生空闲时间段,多个(两个以上),字符;

兴趣标签,多个(两个以上),字符(学生的兴趣标签一定是所有部门特点标签其中的一个)

每个学生有不多于5个的部门意愿(助教测试时测试数据中部门意愿可能会出现空缺,非空缺的部分一定是部门编号中的一个,并按照优先级从高到底的顺序排序)。

实现一个智能自动分配算法,根据输入信息,输出部门和学生间的匹配信息(一个学生可以确认多个他所申请的部门,一个部门可以分配少于等于其要求的学生数的学生) 及 未被分配到学生的部门 和 未被部门选中的学生。

数据生成

最好的一组数据

传送门

过程

在编码开始前,我们原计划所有数据均采用随机生成,如学生学号、部门编号、空闲时间单,通过string数组记下,取出符合条件的使用。然而在生成编号和时间段的时候,我们发现了两个问题:

1、大量数据不符合要求

2、无用的耗时占比大(需要判断是否丢弃重复数据)

参考了网上的一些资料后,再结合我们的实际情况,最后决定采用枚举法 + 随机数rand() + bool数组 生成

考虑因素

数据具有随机性

数据具有时效性,如部门志愿不能出现无的情况

数据具有不重复性,如一个人填的时间段不能有多个相同的

枚举数据

string all_tags[10] = {"reading","programming","film","English","music","dance","basketball","chess","running","swimming"};
string freeweek[7] = {"Mon.","Tues.","Wed.","Thurs.","Fri.","Sat.","Sun."};
string freetimes[8] = {"08:00~10:00","9:00~11:00","10:00~12:00","14:00~16~00","15:00~17:00","18:00~20:00","19:00~21:00","20:00~22:00"};
string all_department_no[20] = {"D001","D002", "D003", "D004", "D005","D006","D007","D008", "D009", "D010","D011","D012","D013","D014","D015","D016", "D017", "D018","D019","D020" };

使用如下条件生成数据

学生方面:

编号:参考福大数计学院计算机系学生号码,格式为031502XXX

空闲时间:两个小时为一个时间块划分,避免午休和饭点,化为8:00~10:00,9:00~11:00,14:00~16~00,15:00~17:00,18:00~20:00,19:00~21:00,20:00~22:00共7个时间段,按时间块随机取2~7个

部门选择意愿:从部门编号中随机选取5个以内,部门编号按题设要求为"D001,D002,D003...."

兴趣标签:参考部门特色,选取了英语、编程、阅读、音乐等兴趣

部门方面:

部门编号:按题设要求为"D001,D002,D003...."

活动时间段:同样以两个小时为一个时间块划分,避免午休和饭点,化为8:00~10:00,9:00~11:00,14:00~16~00,15:00~17:00,18:00~20:00,19:00~21:00,20:00~22:00共7个时间段

特色标签:从标签池中选若干个,参考部门特色

人数上限:参考部门实际需求,院级学生部门的人数区间在[10,15]范围中

数据建模及匹配程序的思路及实现方式

1、程序模型

主要由三部分组成:生成数据程序、匹配算法程序、json格式输入输出程序



2、数据模型

学生模型:

1)学号:按顺序生成

2)空闲时段:从枚举的日期和时间段中组合,用bool数组标记

3)空闲时段个数

4)兴趣标签:从枚举的兴趣标签中挑选,用bool数组标记

5)兴趣标签个数

6)部门意愿:从枚举的部门意愿中挑选,用string数组记录

7)部门意愿个数

8)加入的部门个数

9)在所意愿的部门中综合得分:计算方法在后面匹配算法中提到

部门模型:

1)部门编号:按顺序生成

2)招收学生数的上限

3)兴趣标签:从枚举的兴趣标签中挑选,用bool数组标记

4)兴趣标签个数

5)空闲时段:从枚举的日期和时间段中组合,用bool数组标记

6)空闲时段个数

3、匹配程序的思路

1) 先列出当初我们讨论的头脑风暴(注:由于我们算法能力不足,并没有完全解决所提出的问题)

a) 基于学生在每个意愿部门上的得分来进行分配,显然更加简洁明了

b) 计算学生对每个部门的相应得分要考虑: 这个部门在学生部门意愿优先度、 部门活动时间和学生空闲时间的重合度、部门标签和学生兴趣标签重合度、 当前学生已加入的部门个数(加入个数越多得分越低);

c) 当学生因为得分最低而被淘汰时,其得分全都要重新计算;

d) 当学生的一个空闲时间段和两个意愿部门的活动时间重叠时,则该时间段计算到意愿优先度高的部门;

e) 当学生的部门意愿为空或者学生一个部门意愿都没中选,考虑把学生分配给部门意愿外的部门;

f) 当学生的空闲时段和部门活动时段没有一个重合时,该学生的得分应该置0。

2) 计算得分的规则:

部门意愿优先度得分:第一意愿部门得50分,第二意愿部门得30分,第三、四、五意愿部门得10,7,3分。站在学生角度上,第一个意愿部门应该在得分中占较大比重。

时间重叠度得分:用1小时来考虑,重叠1小时得40分,2小时得50分,3小时以上得55分,如果一次都没有分数置为0。学生必须得有时间来参加部门活动,所以时间重合度也应占较大比重,但同时学生也不要把太多时间用于部门,所以当时间重合超过3小时以上得分不变。

标签重合度得分:重合一个标签相符得10分,标签越多,就越和部门志趣相投,所以成正比;

3) 实现方法:

  该匹配算法目的为得到一个让学生和部门都尽量满意的分配方案。

  首先从学生的第一意愿部门出发,如果该部门招收学生人数未到上限,那么就中选;如果招收学生人数已达上限,那就得分和已招收的学生中最低得分比较,高于最低得分就取代最低得分的那个同学,低于最低得分那该第一意愿就废弃。

  同理,再从第二意愿出发... ...

  使用这种方式可以确保部门招收的同学都是排名前列的,同时同学的每个意愿都经过考虑不会有遗漏。

4)结果分析:

  大体上看,其结果还是满足预期的。但是就是未得到分配的学生有点多,这是因为我们算法是根据学生的部门意愿来进行分配的,一旦300个人都选择热门部门,就一定会有大量的人落选,要想解决这个问题就需要改进算法,实现想法 e)考虑把学生分配给部门意愿外的部门。希望后面能有时间把想法都实现了。

有学生申请的部门的申请列表中,将学生先按时间符合排序,再按标签符合排序,取所有可取的,且少于部员数量限制的学生,加入 matched 数组,否则再将申请列表剩下的学生按时间符合排序,取所有可取的,且少于部员数量限制的学生,加入 matched 数组。

代码规范

本次结对作业用github进行代码管理,两人统一使用叶己峰的账号进行提交。

主要遵循以下几个规范

对变量名命名使用驼峰式(json数据的用下划线衔接单词),且变量名有意义,不乱取

if、for、do、while、case、switch、default等语句自占一行

程序块采用缩进风格编写,缩进的空格数为4个

//部门结构体
struct Department
{
string department_no;       //部门编号(唯一确定值),字符
int member_limit;          //各部门需要学生数的要求的上限,单个,数值,在[10,15]内;
int tags_num;              //部门的特点标签个数
int tags[10];             //各部门的特点标签,多个(两个以上),字符;
int event_schedules_num;     //各部门的常规活动时间段个数
int event_schedules[7][8];  //各部门的常规活动时间段,多个(两个以上),字符。
};

//常规活动时间段
dep[i].event_schedules_num = unsigned(rand()%6) + 2;
for(int j = 0; j < dep[i].event_schedules_num; j++)
{
int t1 = unsigned(rand()%7);
int t2 = unsigned(rand()%8);
if(dep[i].event_schedules[t1][t2]==1)
j--;
else
dep[i].event_schedules[t1][t2] = 1;
}


结对感受

刚看到题目的时候,我意识到了这次作业的工作量远远大于前几次软工实践作业,然而完成效果却会比前几次的差很多,原因主要是国庆放假回家的缘故了,由于家里学习条件较差,主要工作都是在假期前和回到学校后完成的。我们在放假回家前先大致讨论过了思路和方案,两人的分工大致是,练斐弘负责json数据的读入和输出,叶己峰负责匹配算法,剩下的细节由两人共同讨论完成。我本以为关于json数据这部分会较轻松些,因为之前玩过前端,用javascript来处理json数据听方便的。没想到却碰上了大麻烦,在读入的问题上,卡了有两天时间,最初采用cjson来读取数据,可是编译器频频报错cjson的函数undefined,检查了几遍头文件的引入,都没找到问题,又上网找了资料,仍然无法解决,无奈弃坑,转用比较多人使用的jsoncpp,相对于cjson来说,jsoncpp函数的调用更简洁明了一些,然而在jsoncpp的配置中,还是碰到了一些坑,幸运的是,在网上找到了一份教程,也算是找到了个小捷径。这里,也要向队友表达谢意和歉意,叶己峰同学做事严谨认真,本来可以早些提交代码的,他还审核过了多次,debug了挺久,才得到我们最后更好的作品,而相比之下,我感觉我要学习和努力的还有更多。

本次结对作业虽然感觉完成情况不好,但是还是有些收获,主要如下几点

看到报错信息,不要马上复制黏贴问百度,先翻译!自己解决!网上很多论坛的答案也不是正确的,盲目照改会出现很大问题

编码规范还是很重要的,在没注释的情况下,看懂队友的代码是一件非常痛苦的事情,先树立规范,再编写代码,磨刀不误砍柴工。

不同语言对于同样数据的处理是有很大区别的!比如json数据,不能盲目用老方法处理,否则会吃大亏。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: