结对第二次作业



结对成员


[周琪文 031502642](http://www.cnblogs.com/qiwenzhou/) [张旗 031502243](http://www.cnblogs.com/neveslalala/)


Github链接


[点击这里进入github](https://github.com/qiwenzhou/match)

最“好”数据&原理以及所考虑的因素(张旗)


最“好”数据

[github的BIN目录中哦](https://github.com/qiwenzhou/match/blob/master/BIN/input_data.txt)

"数据生成"程序的原理以及所考虑的因素


生成原理

这里以生成部门标签为例,先构建一个存放所有标签的数组tags[9],存放"film", "English", "reading", "music", "dance", "basketball", "chess",部门随机生成2~5(tags_cnt = rand() % 4 + 2)个标签(需考虑去重),在for循环中随机生成tags_num = rand() % 10(去重),就是部门标签,以此类推。

考虑因素

1. freetime 生成时间有两种,考虑到上课时间冲突,常规上课时间少生成一点,非上课时间多生成一点,时长都是两个小时。 2. 标签随意生成 2-5个随机,不重复,从总的标签集合(数组)中取。 3. 意向部门0-5个随机,不重复,意向部门编号从总的集合(数组)中取。 4. 部门收的人数个数memberlimit在8-16个。 5. 生成有空时间没有个数限制,生成时的规律是一定概率(上课时间为20%,非上课时间为80%)向下生成,连续生成的概率减少10%到40%。 一天二十四个小时分成12个时间片,七天生成84个片生成空闲时间片。 6. 学号按照一定规则排列,以我们学院为主(031502xxx),不重复。


数据建模及匹配程序的思路及实现方式(周琪文所做)


>提供输入包括: 20个部门 部门编号(唯一确定值),字符; 各部门需要学生数的要求的上限,单个,数值,在[10,15]内; 各部门的特点标签,多个(两个以上),字符; 各部门的常规活动时间段,多个(两个以上),字符。 300个学生 学生编号(唯一确定值),字符; 学生空闲时间段,多个(两个以上),字符; 兴趣标签,多个(两个以上),字符(学生的兴趣标签一定是所有部门特点标签其中的一个) 每个学生有不多于5个的部门意愿(助教测试时测试数据中部门意愿可能会出现空缺,非空缺的部分一定是部门编号中的一个,并按照优先级从高到底的顺序排序)。 实现一个智能自动分配算法,根据输入信息,输出部门和学生间的匹配信息(一个学生可以确认多个他所申请的部门,一个部门可以分配少于等于其要求的学生数的学生) 及 未被分配到学生的部门 和 未被部门选中的学生。
建模:使用不定长向量vector。先读取文件,把文件转化成数组形式,每一个同学用同一个下标表示,并封装。
vector<vector<string>> studentsTime; //学生空闲时间
vector<vector<string>> studentsApp; //学生的申请部门
vector<vector<string>> studentsID; //学生学号
vector<vector<string>> studentsTags; //学生兴趣标签

vector<vector<string>> deptNo; //部门编号
vector<vector<string>> deptTags; // 部门标签
vector<vector<string>> deptEvent; //部门常规时间
vector<vector<int>> deptMumLimit; //部门人数限制

建三张搜索表,分别是: - 标签到部门下标的字典。 - 时间到部门下标的字典。 - 部门No到部门下标的字典。 例如,标签到部门下标的字典( map < string,set < int > > ): - map中string 是特征标签。 - set是集合,存包含标签的部门的下标,用整型表示。
tags 含有该tag的部门
film 实践外联部
dance 文化部
basketball 体育部

在匹配时,取出学生的标签对应的部门集合,和学生申请的部门集合,进行交运算,得到set1,再把set1,和空闲时间对应的部门集合进行交运算,得到最后的集合。 找到符合个人兴趣和时间的集合后,再检查是否已加入,重复,无法加入(已加入五个部门),部门已达到人数上限等问题。

具体代码


读取文件并存储


/*读入部门数据,并存储*/
	for (int i = 0; jv["departments"][i].asBool(); i++)
	{
		//ID
		vector<string> tID;
		tID.push_back(jv["departments"][i]["department_no"].asString());  //读入部门号并放入vector中
		dict_no2index.insert(pair<string, int>(jv["departments"][i]["department_no"].asString(), i));//将vector放入容器中,形成二维数字

		//同样的方法读入时间段,标签,和人数限制,同样用vector组成的二维数组保存起来
		deptNo.push_back(tID);
		//time
		vector<string> tTime;
		for (int j = 0; jv["departments"][i]["event_schedules"][j].asBool(); j++)
		{
			//string ss = """ + jv["departments"][i]["event_schedules"][j].asString() + """;
			tTime.push_back(jv["departments"][i]["event_schedules"][j].asString());
		}
		deptEvent.push_back(tTime);

		//tags
		vector<string> tTags;
		for (int j = 0; jv["departments"][i]["tags"][j].asBool(); j++)
		{
			tTags.push_back(jv["departments"][i]["tags"][j].asString());
		}
		deptTags.push_back(tTags);

		/[表情]mit
		vector<int> tLimit;
		tLimit.push_back(jv["departments"][i]["member_limit"].asInt());
		deptMumLimit.push_back(tLimit);
	}

构造字典


map<string, set<int>> dict_time;  //建造时间段->部门下标的字典
	for(int i = 0;i < deptEvent.size();i++)  //遍历部门
	{
		for(int j = 0;j < deptEvent[i].size();j++)  //遍历部门的时间段
		{
			if(dict_time.count(deptEvent[i][j]) == 0)  //如果时间段没有在这个字典中
			{
				set<int> frees;  //添加字典项
				frees.insert(i);
				dict_time.insert(pair<string, set<int>>(deptEvent[i][j],frees));
			}
			else
			{
				dict_time[deptEvent[i][j]].insert(i);  //如果时间段已存在,就添加到对应的集合中
			}
		}
	}

利用集合的交运算进行匹配(截取标签匹配的部门代码,说明程序匹配的原理)


for (int i = 0; i < studentsID.size(); i++) //取出一个学生
	{
		set<int> apps;
		set<int> apps2;
		for (int j = 0; j < studentsApp[i].size(); j++)  //获得该学生的意向部门集合
		{
			//cout << studentsApp[i][j] << " ";
			//cout << dict_no2index[studentsApp[i][j]] << " " << endl;
			apps.insert(dict_no2index[studentsApp[i][j]]);
		}
		for (int j = 0; j < studentsTags[i].size(); j++) //进行标签匹配,取出学生的一个标签
		{
			set<int>::iterator it;
			set<int> tags = dict_tags[studentsTags[i][j]]; //根据字典找到该标签对应的社团集合
			/*cout << "tags ";
			for (it = tags.begin(); it != tags.end(); it++)
			{
				cout << *it << " ";
			}
			cout << endl;
			cout << "apps ";
			for (it = apps.begin(); it != apps.end(); it++)
			{
				cout << *it << " ";
			}
			cout << endl;*/
			set<int>::iterator it1;
			set<int>::iterator it2;

			for (it1 = apps.begin(); it1 != apps.end(); it1++)  //进行循环,完成集合交运算
			{
				bool remove = true;;
				for (it2 = tags.begin(); it2 != tags.end(); it2++)
				{
					if (*it1 == *it2)
					{
						remove = false;
						break;
					}
				}
				if (!remove)
				{
					apps2.insert(*it1);
				}
			}



代码规范


1. 使用空行来分割逻辑,易于解读。 - ![](http://images2017.cnblogs.com/blog/885599/201710/885599-20171009191542293-1270816512.png) 2. 使用注释和花括号——上下对齐式。 - ![](http://images2017.cnblogs.com/blog/885599/201710/885599-20171009200144043-954590076.png) 3. 不使用的代码暂且注释,因为工程不大,所以这里先注释掉,并且注明注释原因。若项目庞大,则考虑使用git,来保存旧版本,便于回滚。 - ![](http://images2017.cnblogs.com/blog/885599/201710/885599-20171009191553199-525072470.png) 4. 不用中文拼音做变量名。字段名全部使用中文拼音缩写,令人费解,而且非常别扭。对变量赋予实际英语意义,便于理解。 - ![](http://images2017.cnblogs.com/blog/885599/201710/885599-20171008171526731-2053027893.png)


结果评估


根据匹配的结果,对自己生成的数据,没有学生匹配到的个数在10个左右,一般没有部门收不到人。 对这样的结果不太满意具体如下: 1. 在匹配时对个人之间的优先级没有进行约束,是先到先进。 2. 在针对时间匹配上的处理需要优化,例如,针对部门时间14:00~16:00,个人空闲时间14:00~17:00并不会匹配。 3. 在数据结构上,对数据的匹配速度上还不是很满意。 问题出在处理的规则太简单,目前想到的解决方法与优化为: 1. 可以将第一个填写的志愿部门作为第一志愿,优先级最高,以此类推,但是由于水平与时间有限,会在以后完善。 2. 可以将数字进行大小比较,目前在程序中还未实现,会在以后完善。 3. 程序还需要进一步优化。 4. 还需要学会用github回退到以前版本,这样可以减少大量冗余注释。


结对感受


###主要的分工是:张旗负责生成函数,周琪文负责匹配。 这次结对非常的艰辛,因为国庆期间有人回家了,不能直接的讨论,有人要早起贪黑的去练车考驾照,所以能够一起讨论的时间少之又少,我们只能在晚上的时候进行讨论,分析问题。白天的时候有空的人就赶快敲代码,最终还是在时间截止之前将程序做完了。这次和以往的作业非常不同,可以说是第一次合作完成一个小程序,在这里一定要强调一下**交流的重要性!!**没有交流,一个人做再多也无济于事!!还需要重新再做!所以正印证了栋哥在软工课上说的**越早开始做程序,最后完成的就会越晚**的真理! 那么在这里我说一下生成函数使我最头大的问题就是要从实际生活出发,考虑很多细节。一开始只是马马虎虎的做了一个生成函数,发现很不切实际,并且一开始做出来的格式不正确,不能正确匹配,导致出现很多的bug。经过我们的讨论,确定了很多的细节,才做出来了符合实际生活并且能够匹配的生成函数。
除此之外,这次使用到了代码规范,我们也深刻体会到了,为了更好的拼接代码,一个合适的代码规范的重要性。在没有制定代码规范之前,我们彼此互相看不懂对方的代码,导致代码工作停滞,制定了代码规范之后,代码的可读性大大提高。
PS:经过这次结对作业,我发现我还是更擅长UI啊TT

原文地址:https://www.cnblogs.com/neveslalala/p/7637965.html