zoukankan      html  css  js  c++  java
  • 04.毕设导师智能匹配

    031402508 洪佳铭

    031402516 黄瑞钰

    项目源码猛戳此处⬅️

    问题描述

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

    问题分析

    本次算法采用的是Gale-shapley算法来解决配对的问题

    • Gale-shapley算法介绍(摘自《硕士研究生与导师的双向选择的最优匹配》——向冰,刘文君)



    • 如何实际应用Gale-shapley算法?
      我们发现Gale-shapley算法需要在信息对称且完全的情况下,按照偏好,进行相互选择。这次任务导师相对于学生信息是公开的,学生可以自主根据喜欢的导师进行志愿填写。然而这次没有让导师来选择学生,而是要自动分配学生,所有学生相对于导师信息其实是不公开的,这样就导致双方的信息是不对称的。 所以我们通过学生的绩点高低来排序(若绩点相同,就按照学号大小来排列),这样导师就按照该排序来模拟导师偏好,来进行学生分配。从而就可以满足Gale-shapley算法需要在信息对称且完全的情况下,选择的双方按照自己的偏好进行选择的条件,从而得出最优的匹配。

    代码分析

    • 随机生成数据

    导师的ID、希望带领的学生个数,学生的学号、绩点、五大志愿均随机生成(部分代码如下)

    /**
    	 * 自动生成导师数据用于测试
    	 * 格式为: 导师姓名       导师ID    希望带领学生个数
    	 * Demo: 导师01     7561         7
    	 * @param tutorNum
    	 */
    	public void createTutorData(int tutorsNum) {
    		try{
    		
    			Writer writer = new FileWriter("testData/tutorsData.txt");
    	        BufferedWriter buffWriter=new BufferedWriter(writer);
    	        
    	        buffWriter.write("导师姓名" + "     " 
    	        		+ "教师ID" + "     " 
    	        		+ "导师希望带领学生数");
    	        buffWriter.newLine();
    	        
    	        for(int i = 1;i <= tutorsNum;i++) {
    	        	if(i < 10) {
    	        		buffWriter.write("导师0" + i + "       "
    	        				+ createRandomTutorID() + "              " 
    	        				+ createRandomLeadNum());
    	        	} else {
    	        		buffWriter.write("导师" + i + "       " 
    	        				+ createRandomTutorID() + "              " 
    	        				+ createRandomLeadNum());
    	        	}
    	 	        buffWriter.newLine();
    	        }
    	
    	        buffWriter.close();
    	        writer.close();
    	        System.out.println("导师测试数据写入成功!");
    		} catch(IOException e) {
    			System.out.println("导师测试数据文件写入错误:" + e.getMessage());
    		}
    
    	}
    	
    	/**
    	 * 自动生成学生数据用于测试
    	 * 格式为: 学生姓名           学号             绩点            第一志愿        第二志愿        第三志愿        第四志愿        第五志愿
    	 * Demo: 学生01   231402001  3.21     1234     2234     1234     1234      1234
    	 * @param studentsNum
    	 */
    	public void createStudentData(int studentsNum) {
    		try{
    			Writer writer = new FileWriter("testData/studentsData.txt");
    	        BufferedWriter buffWriter = new BufferedWriter(writer);
    	        buffWriter.write("学生姓名" + "      "
    	        		+ "学生学号" + "        " 
    	        		+ "学生绩点" + "        " 
    	        		+ "第一志愿" + "        " 
    	        		+ "第二志愿" + "        " 
    	        		+ "第三志愿" + "        " 
    	        		+ "第四志愿" + "        " 
    	        		+ "第五志愿");
    	        buffWriter.newLine();
    	        
    	        for(int i = 1;i <= studentsNum;i++) {
    	        	if(i < 10) {
    	        		buffWriter.write("学生00" + i + "       " 
    	        				+ createRandomStudentNum() + "       " 
    	        				+ createRandomGradePoint() + "           " 
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor());
    	        	
    	        	} else if (i < 100){
    	        		buffWriter.write("学生0" + i + "       " 
    	        				+ createRandomStudentNum() + "       " 
    	        				+ createRandomGradePoint() + "           "
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor());
    	        	} else {
    	        		buffWriter.write("学生" + i + "       " 
    	        				+ createRandomStudentNum() + "       "
    	        				+ createRandomGradePoint() + "           "
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor() + "            "
    	        				+ createRandomTutor());
    	        	}
    	 	        buffWriter.newLine();
    	        }
    	
    	        buffWriter.close();
    	        writer.close();
    	        System.out.println("学生测试数据写入成功!");
    		} catch(IOException e) {
    			System.out.println("学生测试数据文件写入错误:" + e.getMessage());
    		}
    	}
    	
    
    • 对学生进行排序

    将学生按照绩点高低(若绩点相同,按照学号大小)排列

    public class SortByGradePoint implements Comparator{
    
    	
    	//按绩点从高到低排列,如果绩点相同,则按照学号从小到大排
    	@Override
    	public int compare(Object o1, Object o2) {
    		// TODO Auto-generated method stub
    		if(((StudentInf)o1).getGradePoint() < ((StudentInf)o2).getGradePoint()) {
    			return 1;
    		} else if(((StudentInf)o1).getGradePoint() > ((StudentInf)o2).getGradePoint()) {
    			return -1;
    		} else if((((StudentInf)o1).getsNum().compareTo(((StudentInf)o2).getsNum())) < 0){
    			return 1;
    		} else {
    			return -1;
    		}
    			
    	}
    	
    }
    
    • 核心算法:分配导师
    1. 根据学生们的志愿一轮一轮的选择自己中意的导师。(如果该学生该轮志愿选的导师,其带领学生人数已经满了,则进行下一个学生的分配。该学生需要等待下一轮志愿再进行分配。)
    2. 每一轮过后都会有一些学生被分配,当五轮(五个志愿)都结束后,这个算法就结束了。
    3. 在这个算法中,100个学生共需要进行5轮选择,因此,算法最多100*5轮循环就结束了。
    /**
    	 * 分配导师算法
    	 * @param tutorsMap
    	 * @param studentsList
    	 */
    public static void assignmentTutor(HashMap<String,TutorInf> tutorsMap,ArrayList<StudentInf> studentsList,ArrayList<StudentInf> isAssignmentStudentsList) {
    		for(int i = 0 ;i < 5;i++) {![image](http://note.youdao.com/favicon.ico)
    			Iterator<StudentInf> iterator = studentsList.iterator();
    			while (iterator.hasNext()) {
    				StudentInf studentInfTemp = iterator.next();
    				TutorInf tutorInftemp = (TutorInf)(tutorsMap.get(studentInfTemp.getTutorsWish().get(i)));
    				if(tutorInftemp.getLeadedNum() < tutorInftemp.getLeadNum()) {
    					
    					tutorInftemp.setLeadedNum(tutorInftemp.getLeadedNum() + 1);  //导师带领人数+1
    					tutorInftemp.getLeadStudents().add(studentInfTemp.getsName() + "(" + studentInfTemp.getsNum() + ")"); //学生名字、学号添加到导师带领学生列表
    					studentInfTemp.setAssignment(true); //标记该学生已分配导师
    					studentInfTemp.setMyTutorName(tutorInftemp.getTname());//记录该学生的导师姓名
    					studentInfTemp.setMyTutorID(tutorInftemp.gettID());//记录该学生的导师ID
    					isAssignmentStudentsList.add(studentInfTemp);  //将该学生添加到已将分配的学生List
    					iterator.remove();
    					
    				} else if (tutorInftemp.getLeadedNum() == tutorInftemp.getLeadNum()) {
    					continue;
    				}
    			}
    		}
    	}
    

    代码测试结果分析

    • 自动生成的数据(部分截图)

    • 测试结果(部分截图)

    • 分析
      在选择的双方信息对称的前提下,Gale-shapley算法很好的解决了导师分配的问题。但是还是会有少数学生没有分配到导师。最优情况是所有学生都得到了分配,最坏情况则是有十多个学生未得到分配。

    算法优劣分析及后期改进

    从算法本身来说,Gale-shapley算法完全可以满足本次问题的要求。后期改进的话我们觉得可以从匹配双方的偏好方面进一步优化,使得分配更加合理,这次导师偏好完全只是依靠学生绩点和学号来模拟的。还有就是从随机数据的产生方面加入更多的限制条件,使得产生的随机数据更加贴近现实。

    第二次结对感受

    • 洪佳铭(031402508)
      本次的结对任务说实话并不是我的强项,最终磕磕绊绊地完成了基本目标,但是还是暴露出我对编码这方面的不足,这需要我后期投入更多的时间和精力去多多接触。很感谢队友,他承担了很大一部分的任务,果然是中国好队友。

    • 黄瑞钰(031402516)
      最初看到这个作业的时候,不知道怎么开始动手,前几天没什么进度。后来通过学校图书馆查了一些关于研究生导师选择的论文,发现Gale-Shapley 算法可以很好的解决分配的问题。于是又阅览了《算法的乐趣》关于Gale-Shapley算法的一些应用实例。然而当要开始写代码的时候,还是一脸懵逼。由于好久没写Java,连语法都有点忘记。脑子里已经有思路了,但是就是不知道怎么用代码来实现,然后就又拖了一两天。 后面把整个任务分解成一个一个小问题。从数据的文本输入输出,到类的排序,再到Gale-Shapley算法的实现,不断地百度啊百度,一步一步逐渐完善。 感觉前期的拖延,很大一个原因是因为对大一点、麻烦一点、不熟悉的问题,内心不愿意立马去面对。有点被困难吓到了,从而不知道如何去动手来解决。可是当你把大的问题拆解成小问题,一个一个去解决,真的就不一样了。

    本次的亮点

    这次最大的亮点是发现了Gale-shapley算法,这个算法很好地解决了我们的问题,为我们提供了很好的思路。

    参考资料

    1. 王晓华。《算法的乐趣》第七章、稳定匹配与舞伴问题
    2. 向冰,刘文君。硕士研究生与导师的双向选择的最优匹配
  • 相关阅读:
    jQuery 小特效【文本框折叠隐藏,展开显示】【下拉菜单】【颜色渐变】【弹窗+遮罩】
    jQuery 【事件】【dom 操作】
    jQuery 【选择器】【动画】
    LINQ 小项目【组合查询、分页】
    LINQ 【高级查询】
    LINQ 【增、删、改、查】数据绑定
    WebFrom 【文件上传】
    【转】c# 字符串大小写混合转换
    【转】C#之继承
    类库,通用变量,is/as运算符,委托。
  • 原文地址:https://www.cnblogs.com/codesigner/p/5924929.html
Copyright © 2011-2022 走看看