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. 向冰,刘文君。硕士研究生与导师的双向选择的最优匹配
  • 相关阅读:
    HBase 高性能加入数据
    Please do not register multiple Pages in undefined.js 小程序报错的几种解决方案
    小程序跳转时传多个参数及获取
    vue项目 调用百度地图 BMap is not defined
    vue生命周期小笔记
    解决小程序背景图片在真机上不能查看的问题
    vue项目 菜单侧边栏随着右侧内容盒子的高度实时变化
    vue项目 一行js代码搞定点击图片放大缩小
    微信小程序进行地图导航使用地图功能
    小程序报错Do not have xx handler in current page的解决方法
  • 原文地址:https://www.cnblogs.com/codesigner/p/5924929.html
Copyright © 2011-2022 走看看