鲍亮 031402401 李陈辉 031402409
问题描述:
编码实现一个毕设导师的智能匹配的程序。提供输入包括:30个老师(包含带学生数的要求的上限,单个数值,在[0,8]内),100个学生(包含绩点信息),每个学生有5个导师志愿(志愿的导师可以重复但不能空缺)。实现一个智能自动分配算法,根据输入信息,输出导师和学生间的匹配信息(一个学生只能有一个确认导师,一个导师可以带少于等于其要求的学生数的学生)及未被分配到学生的导师和未被导师选中的学生。
问题分析
该问题的难点在于:学生填写的志愿会偏重于某些导师,导致许多选热门导师的学生最后选不到(由于绩点等原因相对较低),而冷门导师又收不到预期人数的学生。
为了解决该问题制定以下原则:
- 保证匹配结果越多学生选到导师越好;
- 只有选了该导师的学生才有可能成为他的学生;
- 学生的五个志愿平行,志愿顺序不影响结果;
- 选择导师的学生数超出导师预期收取的人数时,按绩点高低选取。
算法设计
为每位导师设置一个权重值p[i],与导师要求人数n[i],选取此导师的学生数s[i]存在如下关系:
该式子的意义是,把n-s的值作为导师被选取的第一优先标准,n的值作为第二优先标准(乘以系数0.1表示其比第一优先标准低一个优先级)。
设置图G[StudentNum][TeacherNum]表示学生选择的导师,初始化如下:i学生选择了j老师,则置G[i][j]=1,否则G[i][j]=0。
现设计算法如下:
- 计算每个导师p值
- 选取p值最高的导师i,取出该导师(不再放回),导师总数tn减去1
- 若是s[i]=0,转步骤1;否则若p[i]>0转步骤4,若p[i]<=0转步骤5
- 对于选择了i的每个学生j,取出该学生(不再放回),输出:该学生为i的学生,若G[j][k]=1(k=0,1,2...TNUM),则G[j][k]=0,s[k]减去1。转步骤6
- 选取选择了i的学生中绩点排前n[i]的学生,取出该学生(不再放回),输出:该学生为i的学生,若G[j][k]=1(k=0,1,2...TNUM),则G[j][k]=0,s[k]减去1。
- 若tn<0,算法结束;否则转步骤1。
代码实现
随机生成以下数据
void InitGradePoints(vector<double> &g){ //初始随机绩点
for(int i=0;i<SNUM;i++){
g.push_back((double)rand()/RAND_MAX*4.0+1.0);
}
}
void InitPeoLimit(vector<int> &p){ //初始随机导师设定人数
for(int i=0;i<TNUM;i++){
p.push_back(rand()%8+1);
}
}
void InitZ(int z1[],int z2[],int z3[],int z4[],int z5[]){//初始随机学生志愿
for(int i=0;i<SNUM;i++){
z1[i]=rand()%TNUM;
z2[i]=rand()%TNUM;
z3[i]=rand()%TNUM;
z4[i]=rand()%TNUM;
z5[i]=rand()%TNUM;
}
}
导师权重初始化
for(int i=0;i<TNUM;i++){ //计算权重值
t[i]=PeoLimit[i];
power[i]+=t[i]*1.1;
}
for(int i=0;i<SNUM;i++){
score[i]=GradePoints[i];
choose=Z1[i];
g[i][choose]=1;
choose=Z2[i];
g[i][choose]=1;
choose=Z3[i];
g[i][choose]=1;
choose=Z4[i];
g[i][choose]=1;
choose=Z5[i];
g[i][choose]=1;
}
for(int i=0;i<SNUM;i++){ //遍历图g,计算权重值
for(int j=0;j<TNUM;j++){
if(g[i][j]==1){
power[j]-=1.0;
s[j]+=1;
}
}
}
每取出一个学生,对图G、各导师权重、学生数更新
void update(int g[][TNUM],int i,double power[],int s[]){
for(int j=0;j<TNUM;j++){
if(g[i][j]==1){
g[i][j]=0;
power[j]+=1.0; //更新权重
s[j]-=1; //学生数减少
}
}
}
ps:输入输出采用文本文件的方式输入
测试结果
测试样本为100个学生,30个老师,输入数据随机生成,统计10次实验结果如下
分析:通过上图可知落选的学生占比极低,为0%至3%,平均是0.7人;而老师落选率则相对较高,最高达23.3%,平均是4.7人,由于这个算法考虑的是使学生尽量选到导师,绩点因素则是次要因素,所以出现以上的情况。
结对感受:
yuaoi:两个人结对确实会发生奇妙的化学反应,两个人的思维碰撞产生的火花是一个人独自思考得不到的。我们两个在对算法的讨论中,各抒己见,并对对方的想法的漏洞提出质疑,才使想法不断改进。两个人分工编程考验了我们的合作能力,将两个程序结合是一个痛苦的过程,但在对友的帮助下我找到自己程序的漏洞,最后成功合并了我们的代码。
Salaka:感觉有了具体的项目做就很明确,在分析问题的时候更有针对性了。和队友讨论分析导师分配问题的时候也探讨了许多的方案,在这个过程中学习到了很多。本来在讨论前期的时候,我们想用很粗略的算法把这个问题解决,后来觉得这样落选的学生就会很多。于是我们讨论了约一个晚上的时间,终于一步一步把这个问题逐渐量化。讨论清楚了以后就开始写代码了,队友解决问题的能力真是神速,我也很配合地完成了自己的部分,所以很开心。
附源代码链接及测试结果
https://coding.net/u/Salaka/p/Tutor-distribution/git