031402429张秀锋 031402310洪志兴git
项目连接:https://coding.net/u/dtewx/p/Pair-Programming-Work/git算法
编码实现一个毕设导师的智能匹配的程序。提供输入包括:30个老师(包含带学生数的要求的上限,单个数值,在[0,8]内),100个学生(包含绩点信息),每一个学生有5个导师志愿(志愿的导师能够重复但不能空缺)。实现一个智能自动分配算法,根据输入信息,输出导师和学生间的匹配信息(一个学生只能有一个确认导师,一个导师能够带少于等于其要求的学生数的学生) 及 未被分配到学生的导师 和 未被导师选中的学生。 编程
此次的做业要求比较简单,条件也比较少,只有输入数据输出结果,重点在于尽可能减小未被分配到的学生数量,但同时也应该知足一些要求,好比学生的绩点排名、志愿顺序等,通过讨论咱们肯定了下面几个原则:学习
1.绩点优先:绩点较高的学生应该有优先权选择导师
2.志愿顺序优先:优先考虑学生前面的志愿
3.学生意愿优先:只把学生分配给他志愿中的导师,不强制分配测试
咱们讨论的方法比较简单,主要是排序的方法,根据对象有下面三种排序方式:编码
1.按绩点分配:把学生按绩点从高到低排序,从第一个学生开始,依次考虑他的五个志愿,若该志愿的导师指望人数不为零则将该学生分配给导师,不然不分配,轮到下一个学生,若五个志愿都没法分配,那么这个学生被剩下。全部学生轮到事后结束。.net
2.按志愿分配:先对学生的绩点从大到小进行排序,而后进行5次循环:对全部学生的第i(i从1到5)志愿按从绩点高的开始分配(只看第i志愿),第i志愿导师限选人数已满就跳过,放到下一次循环(第i+1志愿),直到剩下的学生的全部志愿导师都被选满为止。设计
3.按导师分配:选出有被选择的导师,按导师被选人数从大到小排序并按这个顺序进行:对每一个导师,先把选择他的学生按志愿排列,再对每级志愿按绩点排列,按这个顺序把学生分配给导师直到限选人数满了或者没学生了,轮到下一个导师,全部导师轮到事后结束。code
上述的三种方法都各有特色,其中第一种方法强调绩点,对于绩点高的同窗颇有好处,但绩点低的就很没有优点,很容易落选;第二种方法综合了学生的绩点和志愿顺序,比前者均衡,绩点越高志愿越靠前越能选中;第三种从导师角度选择,也比较均衡,就是导师的顺序对结果影响较大,越靠前的导师越能选中学生,不过对导师排序彷佛不妥。最后咱们选择了第二种方法,虽然并非最好的方法,不过也兼顾了绩点和志愿顺序。对象
三种方法在学生扎堆选择导师时落选的学生都会比较多,不过考虑到学生意愿优先,在没有强制分配的状况下结果也是由学生本身选择的,跟他们的选择分布有很大关系。
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%以上。虽然随机数的结果跟实际上的会有一些差异,但在学生选择较为平均的状况下仍是能保证必定的中选率。另外因为随机数生成时不能保证导师指望人数和老是大于学生总数,结果也会有些误差,形成中选率偏小。测试随机数据只能用来作一个大概的参考,并不能很好地模拟实际状况。总之,仍是要看实际的检验。
咱们所用的算法规则很简单,只是机械地按照排好的顺序进行分配,没有进行权重计算、动态分配,缺少灵活性,不能保证结果是最优的,另外对于一些状况好比扎堆选择不能有效的避免学生落选。
虽然此次的要求中没有导师对学生的选择状况,不过咱们能够在代码中把导师的选择加入规则,当学生被导师接受时照常进行分配,当被拒绝时能够直接排除。
其实就是一些咱们结对合做过程当中遇到的一些小问题,而后想起《构建之法》中老师提到的几个点:
一、一开始咱们的代码中有中文的字符(提示或是注释),在咱们传送文件,另外一人接收后,中文字符就都乱码了。多是环境不一样的缘故,因此按照书中提到的“注释(包括全部源代码)应该只用ASCII字符,不要用中文或其余特殊字符,不然会极大影响程序的可移植性。”因此,咱们就用蹩脚的英语写了注释,尽可能作到简明扼要能让人看懂。
二、第二点也是代码风格的问题,由于曾经就遇到过,原本在实验室写的代码,带回打开后发现缩进变得很别扭,有的长有的段,缘由是“tab键在不一样的状况下会显示不一样的长度,严重感染阅读体验。”因此,咱们就把全部的tab缩进替换成4个空格。
可能这是些小细节,却值得咱们去吸取和学习。
zxf:通过第一次做业的几回交流讨论磨合,此次做业的讨论比上次更像是在真正地讨论问题了,更放得开大胆地讲咱们的想法,队友提出疑问而后再一块儿想改进的方法。在讨论过程当中咱们经常会错意,没有彻底弄清楚队友的意思,更深刻的交流和讨论,这应该也是进一步磨合的过程吧。咱们的默契还有提高的空间!
hzx:此次的做业中咱们采起了很简单的方法来实现,只能说实现了“分配”,算不上是“智能”,虽然随机数模拟的效果还行,我的感受并无很好地达到目标。咱们有进行过讨论,不过没有抓住重点,更多地在考虑一些实际的细节和特殊状况,最后采用了简单的方法,另外因为我编程上比较渣,咱们动手也比较晚,结果就这样了吧,总的来讲还有不少能够改进的地方。