博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

第二次结对编程作业——毕设导师智能匹配

Posted on 2016-09-28 22:03  yuaoi  阅读(334)  评论(4编辑  收藏  举报

鲍亮 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。
现设计算法如下:

  1. 计算每个导师p值
  2. 选取p值最高的导师i,取出该导师(不再放回),导师总数tn减去1
  3. 若是s[i]=0,转步骤1;否则若p[i]>0转步骤4,若p[i]<=0转步骤5
  4. 对于选择了i的每个学生j,取出该学生(不再放回),输出:该学生为i的学生,若G[j][k]=1(k=0,1,2...TNUM),则G[j][k]=0,s[k]减去1。转步骤6
  5. 选取选择了i的学生中绩点排前n[i]的学生,取出该学生(不再放回),输出:该学生为i的学生,若G[j][k]=1(k=0,1,2...TNUM),则G[j][k]=0,s[k]减去1。
  6. 若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