软件工程实践_结对Task2_ student_department_matching
1. 给出结对成员的学号及姓名。
- 结对成员
- 031502506 陈龙江
- 031502529 王国超 click
2.首页给出项目的Github链接。
- github:传送门
3. 贴出你们生成的一组最“好”的数据(这里的数据特指 input_data.txt,数据给出对应链接即可),并详细说明"数据生成"程序的原理以及你们所考虑的因素。**
A: 你说input_data怎么生成啊?
B: 不懂啊,随便吧。
A: 了解。
-
原理:基于随机性原理生成数据
-
因素:考虑到作业的输入数据的要求:
-
对于学生而言:
- 学生数为300人,分成6个班
- 每名学生有唯一的编号(或者说学号)
- 每名学生的空闲时间段的有效区间为[8:0020:00]+[1:003:00],空闲时间段个数的有效区间为[2, 15]个
- 每名学生的部门意愿个数的有效区间为[0, 5],且排在较前面的意愿优先级较高
- 每名学生的标签个数的有效区间为[2, 20]
-
对于部门而言:
- 部门数为20个
- 每个部门有唯一的编号,格式为D0XX
- 每个部门的要求学生数上限的有效区间为[10, 15]
- 每个部门的标签个数的有效区间为[2, 20]
- 每个部门的常规活动时间段的有效区间为[8:0020:00]+[1:003:00],常规活动时间段个数的有效区间为[2, 15]个
-
在综合以上因素的限制下,我们采用随机算法生成input_data
-
将标签限定为:
string tags[] = { "reading", "programming", "film", "English", "reading", "music", "dance", "basketball", "chess", "football", "swimming", "singing", "climbing", "runing", "drawing", "writing", "cooking", "speeching", "piano", "Go" };
-
最“好”的数据,这个“好”是指这一组数据可以得出使得未被分配到学生的部门和未被部门选中的学生的数量尽可能少?还是说这一组数据更加地贴近实际?
-
在我们理解之下,更倾向于使得生成的数据贴近实际,所以我们也倾向于使用随机性的算法来处理。
-
一个好处是,随机,更贴近实际中不同的学生,不同的部门,可能拥有的无法预测的不同属性的情况。
-
但明显的不足是,我们所处理的简单的随机,也同时忽略了实际中一个部门所拥有的标签等属性之间的联系、学生的各项属性之间的联系等等情况。这些联系是我们的数据中无法体现出来的,也并不清楚要如何去考虑这些联系。
-
4.详细说明你们数据建模及匹配程序的思路及实现方式。
- 数据建模及匹配实现
-
首先给出Student和Department的定义
struct Student { bool isSelect; string id; vector<pair<int, int> > time; vector<string> app; vector<string> tags; Student() :isSelect(false) {} }; struct Department { int curNum; int limit; string id; vector<pair<int, int> > time; vector<string> tags; Department():curNum(0){} };
-
以及匹配算法,Match类的主要成员
class Match { public: Match(); ~Match(); void init(); void stu_dep_matching(const char *infile, const char *outfile, int Pattern = 1); private: int APP_COEF; int TIME_COEF; int TAG_COEF; Student students[studentNum + 5]; Department departments[departmentNum + 5]; string numToTime(int num); int timeToNum(string s); int getWeekNo(string s); pair<int, int> dateToNum(string s); void translate(const char *infile); vector<Node> matching(); void writing(vector<Node> &match, const char *outfile); };
-
我们使用
jsoncpp
来解析和生成json格式的文件 -
匹配算法大致由3个部分组成:
- translate:
- 解析输入文件,将student和department对应的数据存到students[]和departments[]中
- matching:
- 我们称满足以下情况的学生和部门无法匹配:
- 学生的意愿中没有相应的部门编号
- 该学生已经被其他部门接纳
- 该部门所接纳的学生人数达到上限
- 在学生和部门可以相互匹配的情况下:
- 我们给每一对可以相互匹配的学生和部门一个匹配系数
match_coef
- 根据每一对的匹配系数从大到小排序,依次匹配
- 匹配系数的计算方式为(根据模式的不同(默认意愿优先),意愿系数/时间系数/标签系数也会不同):
match_coef = 意愿优先级\*意愿系数 + 匹配时间段数\*时间系数 + 匹配标签数\*标签系数
- 我们给每一对可以相互匹配的学生和部门一个匹配系数
- 我们称满足以下情况的学生和部门无法匹配:
- writing:
- 将第2步得到的匹配情况转化成json格式的output_data文件输出。
- translate:
-
5.你们在代码遵循了一定的规范,在博客中描述结对团队遵循的代码规范,并截取部分关键代码佐证说明。
-
采用面向对象风格的实现,将相应的实现封装成类等等
-
示例:如Match类,Generator类等等
-
大括号换行,以下情况除外:
if-else
语句后只有一行代码- 等等
-
示例:
int Match::getWeekNo(string s) { if (!s.compare("Sun")) return 0; else if (!s.compare("Mon")) return 1; else if (!s.compare("Tues")) return 2; else if (!s.compare("Wed")) return 3; else if (!s.compare("Thu")) return 4; else if (!s.compare("Fri")) return 5; else return 6; }
-
命名
- 函数命名采用驼峰式命名法,第一个单词首字母小写,后面其他单词首字母大写。
- 变量命名采用驼峰式命名法和下划线命名法结合
- 类名首字母大写
-
示例:
Class Match { }; int APP_COEF; int TIME_COEF; int TAG_COEF; string numToTime(int num); int timeToNum(string s); int getWeekNo(string s); pair<int, int> dateToNum(string s);
-
等等
6.结果评估。对于程序的匹配结果,你们是否满意?请对你们程序处理结果进行分析。
- 对于自己生成的input_data文件,程序跑出来有将近1/6的学生无法匹配到相应的部门。
- 对于生成的随机数据,可以跑出这样的结果还是可以接受的,当然也无法达到满意的程度。
- 根据输入模式的不同,进行简单的不同属性优先级(如意愿优先/兴趣优先等)的匹配,也可以接受。
- 但是,作为一个匹配程序,这样的结果说明了它还有很大的提升空间、
- 输入数据无法预测,我们不可能通过构造一组能使得匹配程序跑出更优结果的数据来提升我们的程序。
- 那么一个改进的方向是改善匹配的算法:
- 一是设计更加良好的属性系数的值,使得匹配更合理。
- 二是更换算法,考虑跑一个网络流之类的进行改进。
- 除此之外,程序还存在很多的不足,比如:
- 限定了标签/tags的范围,这对于实际是不行的。一个解决方案是采用hash,利用输入中学生的兴趣标签一定是所有部门特点标签其中的一个这一个条件,生成标签。【undo】
- 算法的复杂度
- ...
- 总而言之,算法的改进空间很大,coding路漫漫...
7.已经尝试过结对编码,你一定很多话要说。请发表结对感受,以及两个人对彼此结对中的闪光点或建议的分享。
- 首先就是,拖延癌晚期患者,表示对不起对友...
- 再来就是两个人感觉沟通交流还不是很够吧,结对编码更希望是两个人的同时提升
- 学习了神奇的jsoncpp
- 最后加班加点,恰逢家里有事,忙里偷闲的赶完工,还是挺开心的
- and,在动车上顶着笔记本的最后一点电量写完这篇博客,exciting!
以上。