结队作业-匹配
A同学: 031520609
B同学: 031502610
目录 :
一. 需求分析
1.1 问题是什么?
- 基于现实情况 (部门纳新筛选)
- 按照数据要求,实现生成数据的程序
- 思考及实现分配算法- 要求:
- 20个部门,300个学生;
- 每个部门,有唯一编号,有确切的纳新人数(人数在区间[10, 15]),两个及以上的常规活动时间,两个及以上的特点标签;
- 每个学生,有唯一编号,有[0,5]个部门意愿,优先级从高到底,两个及以上的空余时间,两个及以上的兴趣标签;
- 每个学生的兴趣标签一定在所有部门的兴趣标签中.
- 格式(Json):
- 输入: input_data.txt
- 输出: output_data.txt
1.2 思考点在哪里
关于数据生成程序
- 标签采取随机生成还是要手动存储几个进数组?; - 如何保证每个部门和学生的自己的标签中不会出现重复?(比如A同学同时拥有两个"basketball"); - 如何保证每个部门的常规活动时间、每个学生的空余时间不出现交集?( 比如A同学有两个空余时间 "Wed.16:00~18:00" 和 "Wed.15:00~17:00", 这两个时间之间有交集); - 如何保证学生的兴趣标签一定在部门的特点标签中出现. - 随机选取部门还是?关于匹配算法
- 如何确定部门的优先顺序,即哪个部门先来选学生? - 如何保证学生被某部门选择后,被要求退部的概率比较小? - 部门选择学生的依据是什么? - 根据上述情况分配完成后,是否应该为了凑满部门的纳新人数,将剩下的学生纳入部门?- 思考...
二. 数据构造程序
* 数据: [input-data](https://winforbest.github.io/Dep-Stu/BIN/input_data.txt) * 原理: * 关于标签问题 - 随机生成,多元化,长度在5到15之间 - 首先,生成k个标签(k>40),用C++的STL map 来避免生成的标签重复,将k个标签保存到string tags[] 数组中; - 其次,部门的特点标签从上述生成的k个标签中任意选取不重复的2-10个, 利用tags数组的下标i,用bool型数组mark[]来记录此下标的tags已被部门选用; - 最后,学生从部门的所有标签中(此处采取mark[]来判断是否存在于部门标签中,选择2-10个不重复的标签* 关于部门常规时间和学生的空余时间
- Day采用随机生成1-7, 小时采用随机生成8-22
- 考虑到正常人的作息时间,hour选取在08.00到22.00之间,Day选取在星期一到星期日之间,每个空余时间两个小时,如 "08:00~10.00";
- 格式为xx:00, 分钟部分采用00形式;
- 时间冲突存在于同一天的空余时间的情况,利用三维数组记录,格式为 flag[Day][h1][h2] = true;
* 关于部门编号和学生编号(唯一性)
- 随机生成,部门格式为Dxxxxxx,学生格式为Sxxxxxx,x表示数字(0-9)
* 关于学生部门意愿
- 随机从已生成的部门中选取k个,0 < = k < = 5,并保证被选择的部门至少有一个标签与该学生的兴趣标签一样.
三. 分配算法构造
* 部门选择顺序 - 记录每个部门被选择的次数,越受欢迎的部门,越早进行匹配. * 分配思路 - 采取两轮分配, 无预选模式 - 第一轮 - 计算value = (与部门常规活动时间不冲突数/部门常规活动时间数 + 与部门相同的特点标签数/部门总标签数 + x/y ). (优先级,x表示该部门是该生的部门意愿中的第x个,y表示该生部门意愿总数) - 若学生的空余时间与部门常规活动时间完全冲突,那么value = 0; - 兴趣可以培养,哪怕只有一点点的兴趣. - 若value > 0.3 , 则该生被选中. ( 0.3, 臆想的) - 第二轮 - value = 与部门常规活动时间不冲突数 / 部门常规活动时间数 - 若value > 0.3,则该生被选中. (还是0.3, 十次去三次,emmm..好像也还行吧.如果一次都去不了,就没有啥意义了)-
实现
- 根据分配思路,将部门进行排序;
- 枚举每个部门,进行第一轮选择;
- 未达到纳新人数的部门,进行第二轮选择;
-
代码规范
- 每个功能封装成函数(接口形式),保证功能的独立性,例如: 比较学生的某个空余时间是否可以去参与某一个部门的某一个常规时间;
- 代码整洁,尽量单独成行;
- 每个函数均需加注释, 便于重构及拓展时编写代码.
// ----------------------------- 计算标签度 -----------------------------------
// 标签度 = 吻合的兴趣标签个数 / 部门兴趣标签数
double calTag(int a, int b) {
int i, j, cnt = 0;
int len = dep[b].tlen;
for (i = 0; i < len; ++i) {
int len2 = stu[a].tlen;
for (j = 0; j < len2; ++j) {
if (dep[b].tags[i] == stu[a].tags[j]) {
++cnt;
}
}
}
return 1.0*cnt / len;
}
// ----------------------- 计算重视程度(第几志愿) -----------------------
// 重视程度 = 第x志愿 / 总志愿数
double calChoose(int a, int b) {
int i;
int len = stu[a].alen;
string dno = dep[b].department_no;
for (i = 0; i < len; ++i) {
if (stu[a].applications_department[i] == dno) break;
}
return 1.0*i / len;
}
- 指标
- x = 中选学生数/总学生数
- y = ( SUM(各部门接收人数/各部门纳新人数上限) )/总部门数
- 评测
- 执行了一遍助教的给出的测试样例, 计算结果 x = 0.73 , y = 0.64. 个人觉得还行