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

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:此次的做业中咱们采起了很简单的方法来实现,只能说实现了“分配”,算不上是“智能”,虽然随机数模拟的效果还行,我的感受并无很好地达到目标。咱们有进行过讨论,不过没有抓住重点,更多地在考虑一些实际的细节和特殊状况,最后采用了简单的方法,另外因为我编程上比较渣,咱们动手也比较晚,结果就这样了吧,总的来讲还有不少能够改进的地方。

相关文章
相关标签/搜索