编码实现一个部门与学生的智能匹配的程序

编码实现一个部门与学生的智能匹配的程序


1. 相关信息

1.1 结对成员学号

我:********* ***

大佬:*******10 ***

1.2 项目Github地址

使用Java语言。
https://github.com/Maple27/S-D_Match

2. 作业需求

详细要求点我
编码实现一个部门与学生的智能匹配的程序。
提供输入包括:

* 20个部门:
    * 部门编号(唯一确定值),字符;
    * 各部门需要学生数的要求的上限,单个,数值,在[10,15]内;
    * 各部门的特点标签,多个(两个以上),字符;
    * 各部门的常规活动时间段,多个(两个以上),字符。
* 300个学生:
    * 学生编号(唯一确定值),字符;
    * 学生空闲时间段,多个(两个以上),字符;
    * 兴趣标签,多个(两个以上),字符(学生的兴趣标签一定是所有部门特点标签其中的一个)
    * 每个学生有不多于5个的部门意愿(助教测试时测试数据中部门意愿可能会出现空缺,非空缺的部分一定是部门编号中的一个,并按照优先级从高到底的顺序排序)。

实现一个智能自动分配算法,根据输入信息,输出部门和学生间的匹配信息(一个学生可以确认多个他所申请的部门,一个部门可以分配少于等于其要求的学生数的学生) 及 未被分配到学生的部门 和 未被部门选中的学生。

3. 程序设计

3.1 总体思路

1.读入当前目录下input_data.txt文件。
2.根据读入的文件解析并初始化数据(学生,部门的信息)。
3.将部门根据tags的数量进行排序,tags少的部门优先进行匹配。
4.统计学生在各个部门的优先级。
5.根据学生志愿和优先级,在部门与学生之间进行匹配。
6.构造json数据,输出到output_data.txt。

3.2 结构设计

输入和输出:使用了Gson。gson是泓立建议使用的,我之前对其没有任何了解,都是泓立带飞+照着模板打。我个人的理解:gson就是一个用来处理json输入输出的工具,用的时候需要建立专门的输入类和输出类。有模板就是好-v-。
数据储存:专门建立Student、Department类,用上万能的List数组。这部分很简单。

3.3 关键代码

该部分取自于Match.java

3.3.1 统计学生在各部门的分数

思路很简单:学生一周中每有1小时free_time与部门event_schedule时间对应,优先级+1,学生每有一个兴趣tag与部门tags对应,优先级+2。
兴趣的统计很简单。时间的统计:首先创建存储相关信息的List结构,输入数据后想办法对信息(字符串)进行分割。分割用的方法很土,分割后用来存储信息的字符串名字也很土,但是无伤大雅。最后经过一连串的if判断,进行加分。

public void countStudentScore(){
	for(int i=0;i<departments.size();i++){
		for(int j=0;j<students.size();j++){
			List<String> dTimes = departments.get(i).getActivityTime();
			List<String> sTimes = students.get(j).getFreeTime();
			List<String> dTags = departments.get(i).getTags();
			List<String> sTags = students.get(j).getInterests();
			int score = 0;
			//时间分数统计
			for(int m=0;m<dTimes.size();m++){
				String str1 = dTimes.get(m);
				String[] string2 = str1.split("\\.");
				String[] string3 = string2[1].split("~");
				String[] string4 = string3[0].split(":");
				String[] string5 = string3[1].split(":");
				String day1 = string2[0];
				int start1 = Integer.parseInt(string4[0]);
				int end1 = Integer.parseInt(string5[0]);
				for(int n=0;n<sTimes.size();n++){
					String str2 = sTimes.get(n);
					String[] string6 = str2.split("\\.");
					String[] string7 = string6[1].split("~");
					String[] string8 = string7[0].split(":");
					String[] string9 = string7[1].split(":");
					String day2 = string6[0];
					int start2 = Integer.parseInt(string8[0]);
					int end2 = Integer.parseInt(string9[0]);
					
					if(day1.equals(day2)){
						if(end1<=start2||end2<start1){
							score += 0;
						}
						else if(start1<start2&&end1>start2&&end1<end2){
							score += end1-start2;
						}
						else if(start2<start1&&end2>start1&&end2<end1){
							score += end2-start1;
						}
						else if(start1>start2&&end1<end2){
							score += end1-start1;
						}
						else if(start2>start1&&end2<end1){
							score += end2-start2;
						}
					}
				}
			}
			//兴趣分数统计
			for(int p=0;p<dTags.size();p++){
				String tag1 = dTags.get(p);
				for(int q=0;q<sTags.size();q++){
					String tag2 = sTags.get(q);
					if(tag1.equals(tag2)){
						score += 2;
					}
				}
			}
			//将此部门与学生时间匹配的分数加入学生信息中
			students.get(j).getScores().add(score);
		}
	}
}

3.3.2 部门编号选学生志愿匹配算法

思路:从tags最少的部门开始,先对学生以在该部门的优先级进行排序,再按第一志愿到最低志愿,遍历学生,符合即选中。注释说的很明白了。

public void match_DtoS(){
	for(int i=0;i<departments.size();i++){//部门匹配
		int num = 0,flag = 0;
		//每次对一个部门招募时以学生对此部门的分数对学生进行重新排列
		sortStudent(students, 0, students.size()-1, i);
		for(int j=0;j<5;j++){//志愿匹配
			for(int k=0;k<students.size();k++){//学生匹配
				//超限 下一个
				if(num>=departments.get(i).getLimit()){
					flag=1;
					break;
				}
				//志愿不足 下一个
				if(students.get(k).getWillsSize()<=j) continue;
				String wills = students.get(k).getWills().get(j);
				String no = departments.get(i).getId();
				if(wills.equals(no)){
					//符合志愿条件,根据符合分数进行分配
					departments.get(i).getMembers().add(students.get(k));
					students.get(k).setFlag(1);
					num++;
				}
			}
			if(flag==1) break;
		}
		departments.get(i).setNum(num);
	}
	for(int i=0;i<departments.size();i++){
		for(int p=0;p<departments.get(i).getMembers().size()-1;p++){
		    for(int j=departments.get(i).getMembers().size()-1;j>p;j--){
		      if(departments.get(i).getMembers().get(j).equals(departments.get(i).getMembers().get(p))){
		    	  departments.get(i).getMembers().remove(j);
		      } 
		    } 
		}

	} 
}

4. 数据生成

这里是我们自认为生成“最好的数据”。
数据生成的代码储存于DataMaker.java中。

看了一下题干,大概能总结出数据一共只有这三类:

  1. 纯数字的。这类直接用限定范围的随机数生成就行了。嗯,学号还要考虑用过的不能再用。
  2. 单词类的,比如说部门名称、兴趣名称什么的。这种单词的个数都是有限的,直接弄一个表(数组实现),生成的时候直接从里面随机拿取数据。
  3. 时间。这个就比较麻烦了。我们把字符串各个元素拆开,先随机生成各个部分,最后再拼起来。

想得美,做得难。做到后面我们发现其实细节上的麻烦还真不少。比如说我们要处理诸如时间不能交叉的各种问题,也要慢慢调试时间的拼接格式。

我们考虑到如下情况:学号和部门号不能出现重复,对于同一个学生/部门标签不能重复,学号只能在限定的范围内出现,生成的时间不能交叉重叠,相邻的时间段也要考虑,不会生成奇葩的时间段(比如说凌晨3:00~4:00之类的)。

一些问题我们没有考虑到:
时间只能生成整点,时间不能够跨天。时间生成整点的确是硬伤,有样例数据的诱导因素在,但是做完之后不想改了-v-。时间不能跨天是我们不想做,现实中可能有些部门会进行深夜活动之类的,也会有学生熬夜的,很烦。另外,粗略看来,生成的数据还是无法反映真实世界的情况。暂时就写到这里。

5. 代码规范

缩进格式:Tab。
行宽:一般不做限制,长行应该尽量少。
注释:2行以上的使用/**/,否则使用//
结构:可以使用形如if(cond) do();的结构。{应该挂在括号右边。
类方法:尽量简短。
命名:类名使用大驼峰,函数名、变量名等使用小驼峰,名称过长时可以使用下划线做分割。
示例

Gson gson = new GsonBuilder().setPrettyPrinting().create();
OutputBean outputBean = new OutputBean();
for(int i=0;i<students.size();i++){
	if(students.get(i).getFlag()==0){
		outputBean.getUnlucky_student().add(students.get(i).getId());
	}
}
for(int j=0;j<departments.size();j++){
	if(departments.get(j).getNum()==0){
		outputBean.getUnlucky_department().add(departments.get(j).getId());
	}else{
		AdmittedBean admittedBean = new AdmittedBean();
		for(int k=0;k<departments.get(j).getMembers().size();k++){
			admittedBean.getMember().add(departments.get(j).getMembers().get(k).getId());
		}
		admittedBean.setDepartment_no(departments.get(j).getId());
		outputBean.getAdmitted().add(admittedBean);
	}
}

6. 结果分析

根据生成的数据,返回的结果达到了预设的要求。但是我们的程序的问题还是显而易见的。
首先我们构造的数据还是与真实的情况有所出入。比如说学生的课余时间一般都在周末,以及时间段的划分还跟课程表和固定活动(比如吃饭)有关,这点我们望尘莫及。从tag最少的部门排序,tag多的部门就很难找到人,这不公平。也很容易出现兴趣广泛的学生报了多个tag单一且一致的社团。优先级也有问题,部门没办法筛选出关键时间不能参加活动的学生。诸如此类。

7. 结对感受

第一次尝试结对编程,真的是被大佬带着飞啊。。本来想用c++做,然后泓立建议使用java,我对java的理解也就仅限于基本语法了,结果就是变成了老师-学生的模式-_-。最后嘛,Java知识的确学到了一些。大佬打代码行云流水,我还看不太懂,我就在接盘的时候问这问那。然后到我打的时候寸步难行,大佬在一旁指点。。不过我们一直觉得实际上不太适应结对这种方式,因为打代码的时候实际上人是不喜欢被突然打断的。最后一天代码文件打包上传至github。

posted @ 2017-10-09 22:00  Metak  阅读(587)  评论(1编辑  收藏  举报