zoukankan      html  css  js  c++  java
  • 软件工程实践2017结对项目——第二次作业

    成员

    练斐弘 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:0010:00,9:0011:00,14:001600,15:0017:00,18:0020:00,19:0021:00,20:0022:00共7个时间段,按时间块随机取2~7个
    • 部门选择意愿:从部门编号中随机选取5个以内,部门编号按题设要求为"D001,D002,D003...."
    • 兴趣标签:参考部门特色,选取了英语、编程、阅读、音乐等兴趣

    部门方面:

    • 部门编号:按题设要求为"D001,D002,D003...."
    • 活动时间段:同样以两个小时为一个时间块划分,避免午休和饭点,化为8:0010:00,9:0011:00,14:001600,15:0017:00,18:0020:00,19:0021:00,20:0022: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。
      1. 计算得分的规则:
      • 部门意愿优先度得分:第一意愿部门得50分,第二意愿部门得30分,第三、四、五意愿部门得10,7,3分。站在学生角度上,第一个意愿部门应该在得分中占较大比重。

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

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

      1. 实现方法:
          该匹配算法目的为得到一个让学生和部门都尽量满意的分配方案。
          首先从学生的第一意愿部门出发,如果该部门招收学生人数未到上限,那么就中选;如果招收学生人数已达上限,那就得分和已招收的学生中最低得分比较,高于最低得分就取代最低得分的那个同学,低于最低得分那该第一意愿就废弃。
          同理,再从第二意愿出发... ...
          使用这种方式可以确保部门招收的同学都是排名前列的,同时同学的每个意愿都经过考虑不会有遗漏。
    • 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数据,不能盲目用老方法处理,否则会吃大亏。
  • 相关阅读:
    linux中编译C语言程序
    plsql 基础教程(二)
    plsql 基础教程(一)
    plsql开发笔记和小结
    表的约束
    一道面试题:说说进程和线程的区别
    HashTable实现原理
    HashMap、Hashtable、HashSet三种hash集合的区别
    Eclipse快捷键大全
    Statement、 PreparedStatement 、CallableStatement 区别和联系
  • 原文地址:https://www.cnblogs.com/Mrwho1/p/7643007.html
Copyright © 2011-2022 走看看