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

031402429张秀锋 031402310洪志兴

项目链接:https://coding.net/u/dtewx/p/Pair-Programming-Work/git

要求内容:

**编码实现一个毕设导师的智能匹配的程序。提供输入包括:30个老师(包含带学生数的要求的上限,单个数值,在[0,8]内),100个学生(包含绩点信息),每个学生有5个导师志愿(志愿的导师可以重复但不能空缺)。实现一个智能自动分配算法,根据输入信息,输出导师和学生间的匹配信息(一个学生只能有一个确认导师,一个导师可以带少于等于其要求的学生数的学生) 及 未被分配到学生的导师 和 未被导师选中的学生。 **

问题分析:

这次的作业要求比较简单,条件也比较少,只有输入数据输出结果,重点在于尽量减少未被分配到的学生数量,但同时也应该满足一些要求,比如学生的绩点排名、志愿顺序等,经过讨论我们确定了下面几个原则:

1.绩点优先:绩点较高的学生应该有优先权选择导师
2.志愿顺序优先:优先考虑学生前面的志愿
3.学生意愿优先:只把学生分配给他志愿中的导师,不强制分配

方法设计:

我们讨论的方法比较简单,主要是排序的方法,根据对象有下面三种排序方式:

1.按绩点分配:把学生按绩点从高到低排序,从第一个学生开始,依次考虑他的五个志愿,若该志愿的导师期望人数不为零则将该学生分配给导师,否则不分配,轮到下一个学生,若五个志愿都无法分配,那么这个学生被剩下。所有学生轮到过后结束。

2.按志愿分配:先对学生的绩点从大到小进行排序,然后进行5次循环:对所有学生的第i(i从1到5)志愿按从绩点高的开始分配(只看第i志愿),第i志愿导师限选人数已满就跳过,放到下一次循环(第i+1志愿),直到剩下的学生的所有志愿导师都被选满为止。

3.按导师分配:选出有被选择的导师,按导师被选人数从大到小排序并按这个顺序进行:对每个导师,先把选择他的学生按志愿排列,再对每级志愿按绩点排列,按这个顺序把学生分配给导师直到限选人数满了或者没学生了,轮到下一个导师,所有导师轮到过后结束。

上述的三种方法都各有特点,其中第一种方法强调绩点,对于绩点高的同学很有好处,但绩点低的就很没有优势,很容易落选;第二种方法综合了学生的绩点和志愿顺序,比前者均衡,绩点越高志愿越靠前越能选中;第三种从导师角度选择,也比较均衡,就是导师的顺序对结果影响较大,越靠前的导师越能选中学生,不过对导师排序似乎不妥。最后我们选择了第二种方法,虽然并不是最好的方法,不过也兼顾了绩点和志愿顺序。

三种方法在学生扎堆选择导师时落选的学生都会比较多,不过考虑到学生意愿优先,在没有强制分配的情况下结果也是由学生自己选择的,跟他们的选择分布有很大关系。

算法流程:

1.对学生按绩点进行排序;
2.开始第i轮循环:只考虑第i志愿,从绩点最高的开始,若导师限选人数未满,则将该学生分配给该导师,否则继续下一个学生;
3.五轮循环结束后,输出结果;(输出格式为:“导师号:学生号”,即每个导师被分配到的学生以及已分配的学生数和未分配学生、导师的编号)

流程图:

实现代码:

定义结构体:

struct student{
int sno;
int cho[5];
double gpa;
bool chos;
};
 
struct teacher{
int tno;
int wnum;
int snum;
bool chos;
int stud[8];
};

生成随机数据:

freopen("input.txt","w",stdout);
srand((int)time(0));
for(i=1;i<=snum;i++){
	printf("%d ",i);
	for(k=0;k<5;k++){
		j=1+(int)((float)tnum*rand()/(RAND_MAX+1.0));
		printf("%d ",j);
	}
		gpa=1+(float)((40.0*rand()/(RAND_MAX+1.0))/10);
		printf("%.2f ",gpa);	
}

读取文件:

void readdata(student s[],teacher t[]){
int i,j;
freopen("input.txt","r",stdin);
for(i=0;i<snum;i++){
	scanf("%d",&s[i].sno);
	for(j=0;j<5;j++)
	scanf("%d",&s[i].cho[j]);
	scanf("%lf",&s[i].gpa);
	s[i].chos=false;
}
for(i=0;i<tnum;i++){
scanf("%d%d",&t[i].tno,&t[i].wnum);
t[i].snum=0;
t[i].chos=false;
}
fclose(stdin);
}

利用快排进行排序:

void sort(student s[],int l,int r){
int i,j;  
student x; 
if(l<r){
    i=l;  
    j=r;  
    x=s[i];  
    while(i<j){  
        while(i<j&&s[j].gpa>x.gpa)   
            j--; 
        if(i<j)   
            s[i++]=s[j];
        while(i<j&&s[i].gpa<x.gpa)   
            i++;
        if(i<j)
            s[j--]=s[i];
    }  
    s[i]=x;
    sort(s,l,i-1); 
    sort(s,i+1,r);
}
}

分配及输出:

void fp(student s[],teacher t[]){
freopen("output.txt","w",stdout);
int i,j,x,k=0,h;
for(i=0;i<5;i++)
for(j=snum-1;j>=0;j--){
	x=match(t,s[j].cho[i]);
	if(s[j].chos==false&&t[x].wnum>0){
	s[j].chos=true;
	t[x].chos=true;
	t[x].wnum--;
	t[x].snum++;
	h=t[x].snum-1;
	t[x].stud[h]=s[j].sno;
	k++;
    }
    else continue;
}
printf("Result(Teacher: student):\n");
for(i=0;i<tnum;i++)
	if(t[i].chos==true){
		printf("%d:",t[i].tno);
		for(j=0;j<t[i].snum;j++)
			printf("%d ",t[i].stud[j]);
		printf("\n");
	}
printf("\nNumber of arranged students: %d\n",k);
printf("Unarranged students: ");
for(i=0;i<snum;i++)
if(s[i].chos==false)
printf("%d ",s[i].sno);
printf("\nUnarranged teachers: ");
for(i=0;i<tnum;i++)
if(t[i].chos==false)
printf("%d ",t[i].tno);
fclose(stdout);
}

算法评估

设s为有被学生选择的所有导师的期望人数之和,a为学生总人数,b为用算法实际完成分配的学生人数,若s>=a,则算法应尽量使b接近或等于a;若s<a,则算法应尽可能使b接近或等于s;用y=b/[min(a,s)]来表示算法的分配完成度。由于实际情况下s不小于a,所以用y=b/a来计算。

用随机生成的数据进行了10次测试,每次都是100个学生和30个导师,测试结果如下:

可以看到效果还是可以的,总体的中选率在90%以上。虽然随机数的结果跟实际上的会有一些差别,但在学生选择较为平均的情况下还是能保证一定的中选率。另外由于随机数生成时不能保证导师期望人数和总是大于学生总数,结果也会有些偏差,造成中选率偏小。测试随机数据只能用来做一个大概的参考,并不能很好地模拟实际情况。总之,还是要看实际的检验。

算法不足

我们所用的算法规则很简单,只是机械地按照排好的顺序进行分配,没有进行权重计算、动态分配,缺乏灵活性,不能保证结果是最优的,另外对于一些情况比如扎堆选择不能有效的避免学生落选。

后续改进

虽然这次的要求中没有导师对学生的选择情况,不过我们可以在代码中把导师的选择加入规则,当学生被导师接受时照常进行分配,当被拒绝时可以直接排除。

建议分享

其实就是一些我们结对合作过程中遇到的一些小问题,然后想起《构建之法》中老师提到的几个点:

1、一开始我们的代码中有中文的字符(提示或是注释),在我们传送文件,另一人接收后,中文字符就都乱码了。可能是环境不同的缘故,所以按照书中提到的“注释(包括所有源代码)应该只用ASCII字符,不要用中文或其他特殊字符,否则会极大影响程序的可移植性。”所以,我们就用蹩脚的英语写了注释,尽量做到简明扼要能让人看懂。

2、第二点也是代码风格的问题,因为曾经就遇到过,本来在实验室写的代码,带回打开后发现缩进变得很别扭,有的长有的段,原因是“tab键在不同的情况下会显示不同的长度,严重感染阅读体验。”所以,我们就把所有的tab缩进替换成4个空格。

可能这是些小细节,却值得我们去吸收和学习。

结对感受

zxf:经过第一次作业的几次交流讨论磨合,这次作业的讨论比上次更像是在真正地讨论问题了,更放得开大胆地讲我们的想法,队友提出疑问然后再一起想改进的方法。在讨论过程中我们常常会错意,没有完全弄清楚队友的意思,更深入的交流和讨论,这应该也是进一步磨合的过程吧。我们的默契还有提升的空间!

hzx:这次的作业中我们采取了很简单的方法来实现,只能说实现了“分配”,算不上是“智能”,虽然随机数模拟的效果还行,个人感觉并没有很好地达到目标。我们有进行过讨论,不过没有抓住重点,更多地在考虑一些实际的细节和特殊情况,最后采用了简单的方法,另外由于我编程上比较渣,我们动手也比较晚,结果就这样了吧,总的来说还有很多可以改进的地方。

posted @ 2016-09-30 19:23  dtew  阅读(240)  评论(2编辑  收藏  举报