zoukankan      html  css  js  c++  java
  • 随笔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++,一点一点地写。写完测试以后,感觉挺有成就感的,测试结果还不错,配对成功率很高!

  • 相关阅读:
    POJ1486 Sorting Slides 二分图or贪心
    POJ2060 Taxi Cab Scheme 最小路径覆盖
    POJ3083 Children of the Candy Corn 解题报告
    以前的文章
    POJ2449 Remmarguts' Date K短路经典题
    这一年的acm路
    POJ3014 Asteroids 最小点覆盖
    POJ2594 Treasure Exploration 最小路径覆盖
    POJ3009 Curling 2.0 解题报告
    POJ2226 Muddy Fields 最小点集覆盖
  • 原文地址:https://www.cnblogs.com/zddd/p/5922226.html
Copyright © 2011-2022 走看看