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


    031402313 黄志明 031402431 章鼎

    github链接:https://github.com/cafe3165/Software_Work


    问题重述

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

    问题分析

    共有一百名学生需要选择三十名导师中五位作为自己的志愿,学生中比较有说服力的一项指标是绩点,所以我们先用绩点高低来排名100位学生。
    一开始的想法是按绩点排名来决定分配导师次序,即绩点排名靠前的学生先分配导师,绩点越靠后的同学越后分配导师,但是这样一来就会出现一个问题——大部分成绩靠后的同学很难选到自己想要的导师,这对他们存在着一些不公平,谁说成绩不好的同学中没有某方面的强项呢?经过与队友讨论,我们决定将绩点排名的前20%以及后20%单独划分出来进行导师分配,方法是先按绩点排名相反次序先后来分配后20%的学生,再用绩点排名次序先后来分配后20%的学生。分配完成后,余下的60%的学生,也就是绩点排名在中间的学生,我们采用由两端向中心夹逼的分配方法,即排名第21的同学最先分配,然后是排名第80的同学,再然后是排名第22的同学······直到第50、51名同学完成分配。
    这样的分配方法既能保证成绩优异同学选到自己想要的导师,又能兼顾成绩较差的同学不会一大片的落选。


    代码分析

    基本数据结构

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <string>
    #include <vector>
    #include <algorithm>
    using namespace std;
    //学生结构体
    struct stu {
    	int num; //学号
    	double c; //绩点
    	bool chose; //是否被选择
    	int teacher[6]; //所选择的导师数组
    };
    //导师所拥有学生的结构体
    struct stu2 {
    	int num;
    	double c;
    
    };
    //导师结构体
    struct tea {
    
    	vector<stu2> student; //所拥有的学生结构体向量组
    	int o; //当前所拥有的学生数
    	int up_limit; //所能带学生的最大数量
    	int chosen[9]; //最终所选择的学生数组
    
    };
    

    随机数据生成

    
    	srand(time(0));
    	int ini = 313;
    	int t[tno];
    	for (int i = 1; i <= tno; i++)
    		t[i] = i;
    
    	fprintf(fout,"%d
    ",sno);
    	for (int i = 0; i < sno; i++) {
    		ini++;
    		double c = 2.5;
    		string s="031402";
    		cout << s << ini << " ";
    		c += (rand() % 10) / 10.0;
    		cout << c << " ";
    		int o1, o2, o3, o4, o5;
    		o1 = rand() % tno;
    		o2 = rand() % tno;
    		o3 = rand() % tno;
    		o4 = rand() % tno;
    		o5 = rand() % tno;
    		if(t[o1]>tno||t[o1]<0) t[o1]=tno;
    		if(t[o2]>tno||t[o2]<0) t[o2]=tno;
    		if(t[o3]>tno||t[o3]<0) t[o3]=tno;
    		if(t[o4]>tno||t[o4]<0) t[o4]=tno;
    		if(t[o5]>tno||t[o5]<0) t[o5]=tno;
    		cout << t[o1] << " " << t[o2] << " " << t[o3] << " " << t[o4] << " "
    				<< t[o5];
    		cout << endl;
    
    
    	}
    
    
    
    

    分配算法

    //绩点靠后的20%先排序,按排名先后相反次序进行分配
    
    	for (int i = snum - 1; i > snum - (snum / 5); i--) {
    
    		for (int j = 0; j < 5; j++) {
    
    
    
    			int tno = S[i].teacher[j];	//tno为导师编号
    
    			//判断该导师还有没有剩余名额,有的话将自己注册进去
    
    			if (T[tno].o < T[tno].up_limit) {
    
    				int to = T[tno].o;
    
    				T[tno].chosen[to] = S[i].num;
    
    				T[tno].o++;
    
    				count++;
    
    				S[i].chose = true;
    
    
    
    				break;
    
    			}
    
    			//若果该学生的第一志愿导师满了的话,就跳到第二志愿去选导师,以此类推
    
    			else
    
    				continue;
    
    
    
    		}
    
    
    
    	}
    
    //前20%学生排序,按排名正向先后分配
    
         for (int i = 0; i < snum / 5; i++) {
    
    		for (int j = 0; j < 5; j++) {
    
    			int tno = S[i].teacher[j];
    
    			if (T[tno].o < T[tno].up_limit) {
    
    				int to = T[tno].o;
    
    				T[tno].chosen[to] = S[i].num;
    
    				T[tno].o++;
    
    				count++;
    
    				S[i].chose = true;
    
    				break;
    
    			}
    
    			else
    
    				continue;
    
    		}
    
    
    	}
    
    
    
    	int p = snum / 5;
    
    	int k = (snum * 4) / 5;
    

    snum为学生总人数,每位学生按志愿先后顺序来进行导师分配,若第一志愿导师人数未达到上限,则将该学生分配进去,若第一志愿导师人数已满,则自动换到第二志愿分配,以此类推,如果直到第五志愿导师都被报满,则跳出循环。

    
    //接下来进行排名居中的60%的同学选导师,分为两个部分,同时进行,选择原理相似
    
    	for (int i = 0;; i++) {
    
    		//从21%往后选到50%
    
    		for (int j = 0; j < 5; j++) {
    
    
    
    			int tno = S[p].teacher[j];
    
    
    
    			if (T[tno].o < T[tno].up_limit) {
    
    				int to = T[tno].o;
    
    				T[tno].chosen[to] = S[p].num;
    
    				T[tno].o++;
    
    				count++;
    
    				S[p].chose = true;
    
    				break;
    
    			}
    
    
    
    			else {
    
    
    
    				continue;
    
    			}
    
    
    
    		}
    
    		p++;
    
    		if (p - 1 == k)
    
    			break;
    
    		//从79%往前选择到50%
    
    		for (int j = 0; j < 5; j++) {
    
    			int tno = S[k].teacher[j];
    
    			if (T[tno].o < T[tno].up_limit) {
    
    				int to = T[tno].o;
    
    				T[tno].chosen[to] = S[k].num;
    
    				T[tno].o++;
    
    				count++;
    
    				S[k].chose = true;
    
    				break;
    
    			} else
    
    				continue;
    
    		}
    
    		k--;
    
    		if (p > k)
    
    			break;
    
    
    
    	}
    

    进行排名居中的60%的同学选导师,分为两个部分,同时进行,分配原理与上面相似


    结果分析

    测试数据例子
    输入:

    输出:
    

    输出结果分析

    随机生成了十组数据,平均中选人数为97.1人,还是比较好的。
    再随机生成了十组数据来统计前20%,后20%,以及中间60%的人的中选人数

    发现,只有中间的人选不中导师,说明此算法比较成功的保护了排名靠前跟靠后的同学


    小结与感受

    章鼎

    本次实验看似类似C++编程题,但要考虑的点却相当复杂,如怎么分配学生才可以让未选到导师的学生尽可能少?如何做到对“热门”导师和“冷门”导师的合理分配?什么样的分配是公平公正可以深得同学们人心?考虑的越多就越不知该如何下手,经过不断讨论,我们决定采用这种“朴素”的算法来解决这些问题,让成绩优异的同学如愿以偿的选到理想导师的同时,兼顾成绩落后的同学,减少他们选不到导师的可能,虽说这种做法“牺牲”了中间一小部分同学的利益,但是从分析结果来看效果还是不错的。
    经过几天的摸索和学习,感觉收获还是挺多的,从中学到如何先倾听队友的思路,再加上自己的想法,不急着打断队友,学会倾听下一步才是合作。

    黄志明

    考虑到实际情况,在没见过学生的情况下,导师选择学生一般是根据两点:1.绩点排名 2.志愿顺序 。这就导出了我们的算法,一般情况下,绩点比较低的学生,很容易在绩点排序的情况下,一轮轮地被刷下来,直到五个志愿都选完了都还没选到导师。所以,我们的算法要照顾绩点靠后的同学,保证绩点靠前的同学,让他们先选,中间的同学就算个别没选到一般情况下也不会有太大抱怨,这种算法反而会给靠后的同学带来惊喜。写了好几天的代码,文件的输入输出,大一的C++忘光了,可是用刚学的JAVA很多也是不会,只能重新拿起C++,一点一点地写。写完测试以后,感觉挺有成就感的,测试结果还不错,配对成功率很高!

  • 相关阅读:
    Docker常见应用部署(3)
    数据库 'FileServer' 的版本为 904,无法打开。此服务器支持 852 版及更低版本。不支持降级路径。 无法打开新数据库
    Dockerfile 构建镜像(4)
    DockerHub 镜像仓库(5)
    ASP.NET Core 6.0 中使用 Autofac
    ASP.NET Core 6.0 使用RabbitMQ
    安装node.js环境,构建第一个vue项目
    Chrome 搜索结果始终保持新标签打开
    最短路
    [转载] Open3D显示点云常见方式
  • 原文地址:https://www.cnblogs.com/zddd/p/5922226.html
Copyright © 2020-2023  润新知