31402631 王凌杰
03140264 李烈争
Coding.net链接
问题描述
- 目标
实现一个毕业生导师智能分配的程序.
- 输入
老师:30人、老师要求选择的学生数:0~8
学生:100人、绩点、学生的五个志愿
- 输出
根据输入的信息,输出选择的结果,要求一个学生只能有一个老师,一个老师可以有
0~8个学生,未分配的老师和学生。尽可能少的学生和老师未匹配。
问题分析
第一次讨论的时候,我们打算将各种因素综合起来,合并成老师-学生相互选择的一个权重
然后进行分配,这时候就遇到了下面的问题。影响选择的因素有学生的绩点,志愿,老师的
意愿。在多因素下如何分配各个因素的权重?这个问题讨论了很久,建一个数学模型?有点
困难?各因素乘上一个比例系数,比例系数该如何确定?人为确定吗?如何保证客观公正合理
?匹配一般都是对两个对象建立联系并赋予一定的权值,来体现关系的优先。那么又回到上
面的问题。回过头将导师分配的流程走一遍发现,其实我们不用考虑这样问题。
在流程图中,老师同意学生的选择,对老师来说,不管学生绩点的高低,都是他想要的学生,
所以从老师的角度看,不用管这些学生的先后顺序。但从学生的角度看,绩点某种程度上体现
这个学生那么多个学期的努力。故按绩点将所有学生排序,将绩点高的学生优先分配,然后再
按志愿顺序分配还有名额的老师。执行三轮分配,若还有学生没有选到老师则进行人工干预。
(不过这个概率很低)。
编码环境
Visual Studio 2015
MySql
Navicat For MySql
语言:C#、SQL
代码分析
主函数
static void Main(string[] args)
{
int ResultCount =0; //结果个数
int StudentCount =100; //学生个数
int TeacherCount = 30; //教师个数
DeleteData(); //清空数据
Console.WriteLine("清空数据成功");
RandomStudent(StudentCount); //随机生成学生
Console.WriteLine("随机学生成功");
RandomTeacher(TeacherCount); //随机生成教师
Console.WriteLine("随机教师成功");
Console.ReadLine();
//第一轮选择
StudentChoice("choice");
Console.WriteLine("第一轮学生选导师成功");
TeacherChoice("choice");
Console.WriteLine("第一轮导师选学生成功");
Console.ReadLine();
//第二轮选择
ResultCount = MySqlReadReturnCount("SELECT * FROM result");//获取结果个数
//判断所有学生是否都已经分配完毕
if (ResultCount < StudentCount)
{
StudentChoice("secondchoice");
Console.WriteLine("第二轮学生选导师成功");
TeacherChoice("secondchoice");
Console.WriteLine("第二轮导师选学生成功");
}
else
{
Console.WriteLine("选择导师完毕");
}
Console.ReadLine();
ResultCount = MySqlReadReturnCount("SELECT * FROM result");//获取结果个数
//判断所有学生是否都已经分配完毕
if (ResultCount < StudentCount)
{
StudentChoice("thirdchoice");
Console.WriteLine("第三轮学生选导师成功");
TeacherChoice("thirdchoice");
Console.WriteLine("第三轮导师选学生成功");
}
else
{
Console.WriteLine("选择导师完毕");
}
Console.ReadLine();
}
主要函数分析
随机数的生成
private static void RandomTeacher(int TeacherNumber)//随机生成老师
{
string InsertString;
string TmpID;
string TmpStudentCount;
try
{
for (int i = 0; i < TeacherNumber; i++)
{
TmpStudentCount = NewStudentCount();//随机生成预选学生数
TmpID = NewID();//根据时间随机生成ID
InsertString = "INSERT INTO teacher(TeacherID,StudentCount,ChoiceStudentCount) VALUE('" + TmpID + "','" + TmpStudentCount + "', '0' )";
MySqlWrite(InsertString);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void RandomStudent(int StudentNumber)//随机生成学生
{
string InsertString;
string TmpID;
string TmpGPA;
try
{
for (int i = 0; i < StudentNumber; i++)
{
TmpGPA = NewGPA();//随机生成绩点
TmpID = NewID();//随机生成ID
InsertString = "INSERT INTO student(StudentID,GPA,IsSelect) VALUE('" + TmpID + "','" + TmpGPA + "', '0' )";
MySqlWrite(InsertString);
}
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
}
模拟师生互选函数
private static void StudentChoice(string TableName)//模拟学生选择导师 TableName为进行分配操作的表名
{
//string SelectString = "select * from teacher order by rand() limit 5";
string SelectTeacherString = "SELECT * FROM teacher WHERE StudentCount != ChoiceStudentCount";
string SelectStudentString = "SELECT * FROM student WHERE IsSelect ="+0;
int Count = MySqlReadReturnCount(SelectTeacherString);//还未选满的老师个数
Console.WriteLine(Count);
int StudentCount = MySqlReadReturnCount(SelectStudentString);//还未选中学生的个数
string[] TeacherID = new string[5];
string TmpID;
string[] StudentID = MySqlReadArray(SelectStudentString, "StudentID");//获取还未被选中的学生ID
//每个学生选5个志愿
for(int i = 0;i<StudentCount;i++)// StudentCount 为学生个数
{
TeacherID = MySqlReadRandom(SelectTeacherString, "TeacherID", Count,5);//获取随机的五个志愿老师ID
for (int f = 0; f < WillCount; f++)//WillCount 为志愿个数
{
TmpID = NewID();//生成ChoiceID
string InsertString = "INSERT INTO "+ TableName + "(ChoiceID,StudentID,TeacherID,WillNumber,IsSelect) VALUE('" + TmpID + "','" + StudentID[i] + "','" + TeacherID[f] + "','"+(f+1).ToString()+ "','" + 0 + "')";
MySqlWrite(InsertString);//往志愿选择表(choice)添加数据
Console.WriteLine(TmpID);
}
}
}
private static void TeacherChoice(string TableName)//模拟导师选择学生 TableName为进行分配操作的表名
{
string SelectTeacherString = "SELECT * FROM teacher WHERE StudentCount != ChoiceStudentCount"; //用于查找剩余的导师
string SelectStudentString = "SELECT * FROM student WHERE IsSelect =" + 0; //用于查找剩余的学生给你
string SelectChoiceString = "SELECT * FROM "+ TableName; //用于访问TableName表
string UpdateChoiceString; //用于更新TableName表
string SelectStudentByChoiceString; //用于获取TableName表中的StudentID
string SelectStudentCountByTeacher; //用于获取teacher表中的StudentCount
//随机选择
int ChoiceCount = MySqlReadReturnCount(SelectChoiceString);
Random TmpRandom = new Random();
//暂定百分之五十至百分之九十的选定
int RandomNumber = TmpRandom.Next(ChoiceCount/2, ChoiceCount/10*9);
string[] ChoiceID = MySqlReadRandom(SelectChoiceString, "ChoiceID", ChoiceCount, RandomNumber);
//模拟导师选中学生
for (int i = 0; i < RandomNumber; i++)
{
UpdateChoiceString = "UPDATE " + TableName + " SET IsSelect=" + 1 + " WHERE ChoiceID ='" + ChoiceID[i] + "'";//IsSelect用于判断学生在这轮是否被导师选中
MySqlWrite(UpdateChoiceString);
Console.WriteLine(ChoiceID[i]);
}
//进行分配
//根据学生绩点排序开始分配老师
string SelectStudentOrderGPA = "SELECT * FROM student WHERE IsSelect = 0 ORDER BY GPA DESC";
int StudentCount = MySqlReadReturnCount(SelectStudentOrderGPA);//获取还未被选中的学生个数
Console.WriteLine(StudentCount);
string[] TmpTeacherID = new string[10];
string[] StudentID = MySqlReadArray(SelectStudentOrderGPA, "StudentID");//获取还未被选中的学生ID
for (int i = 0; i < StudentCount; i++)
{
//一个学生有多条选中信息,按志愿顺序开始分配老师
SelectStudentByChoiceString = "SELECT * FROM "+ TableName + " WHERE StudentID = '" + StudentID[i] + "' AND IsSelect = 1 ORDER BY WillNumber ASC";
TmpTeacherID = MySqlReadArray(SelectStudentByChoiceString, "TeacherID");
if (TmpTeacherID != null)
{
for (int j = 0; j < TmpTeacherID.Length; j++)
{
SelectStudentCountByTeacher = "SELECT * FROM teacher WHERE TeacherID = '" + TmpTeacherID[j] + "'";
int TmpStudentCount = int.Parse(MySqlReadReturn(SelectStudentCountByTeacher, "StudentCount"));//获取老师要选的学生总数
int TmpChoiceStudentCount = int.Parse(MySqlReadReturn(SelectStudentCountByTeacher, "ChoiceStudentCount"));//获取老师已选的学生总数
if (TmpStudentCount > TmpChoiceStudentCount)//若老师人数未满
{
//Console.WriteLine(StudentID[i]);
MySqlWrite("INSERT INTO result(StudentID,TeacherID) VALUE('" + StudentID[i] + "','" + TmpTeacherID[j] + "')");//更新结果表
MySqlWrite("UPDATE student SET IsSelect = 1 WHERE StudentID = '" + StudentID[i] + "'");//更新学生数据为已被选中
AllResultCount++;//所有结果条数
TmpChoiceStudentCount++;/老师已选学生数++
MySqlWrite("UPDATE teacher SET ChoiceStudentCount =" + TmpChoiceStudentCount + " WHERE TeacherID ='" + TmpTeacherID[j] + "'");//更新老师数据已选人数
Console.WriteLine(AllResultCount+"学生" + StudentID[i] + "分配成功");
break;/选中老师跳出循环,对下个学生进行分配
}
}
}
}
}
其他函数
结果分析
生成数据
student表
teacher表
控制台界面
第一轮选择
模拟学生选择导师
控制台界面
choice表(志愿表)
100个学生 每个学生5个志愿 总共有500条记录
因为初始志愿导师还没有选择所以IsSelect都为0
模拟导师选择学生
控制台界面
choice表
IsSelect纪录该导师是否选择了该学生
result表:
student表
IsSelect纪录学生是否中选
重复轮数
小结&感想
王凌杰
本次结对编程我学会了git的基本使用,同时也对毕设导师匹配系统有了更为深刻的理解和思考。
本来我们也想像其他组那样用算法全自动匹配,然而考虑到很多数学建模的问题,而且感觉有很
多不符合实际的假设。于是我们决定实现模拟人为选择,再设计匹配方式进行匹配。我们匹配思
路主要在模拟导师选择学生之后,即实现按学生绩点来作为学生进行匹配的顺序的依据,而把志
愿顺序作为单个学生匹配不同志愿导师的顺序依据。
除了匹配,本次让我印象深刻的实现随机不重复的从数据库中调出数据。原本打算用"select *
from teacher order by rand() limit 5"直接在数据库中实现,但效率出奇的低,于是便参考了
一些算法,由于时间较赶最后决定用比较Low的list.contain 来判断。
李烈争
学会Git的基本使用,感谢助教推荐的Git博客,很详细。看学长的博客感叹markdown还可以那样用。
各种锚点。可以,很强!感谢队友的大腿,编码过程中耐心的讲解,我代码的能力有待提高。考虑的
过程中思维不够严谨,遗漏一些重要的点,拖了进度。两个人交流的时候要组织好后表达,可以提高
效率。