結對成員:吳君毅(031502629),吳偉根(031502631)
Github連結:https://github.com/n9705/Dep-Stu
一、 題目要求
構造部門和學生輸入資料的生成程式,實現一個智慧自動分配演算法,根據輸入資訊,輸出部門和學生間的匹配資訊(一個學生可以確認多個他所申請的部門,一個部門可以分配少於等於其要求的學生數的學生) 及 未被分配到學生的部門 和 未被部門選中的學生。
分工情況:基本上是我負責資料生成程式,偉根負責部門學生自動分配演算法,遇到問題互相幫助探討。
二、 資料生成程式
這部分主要是由我負責
首先根據題目要求建立兩個結構體陣列部門和學生,要滿足的條件如下:
學生:
- 空閒時間段(設定最大為12個,且同一天的不同時間段不能重疊,且根據實 際情況,時間不能是晚上10點後到第二天早上8點之間,且空閒時間段以兩小時為單位)
- 學號(不可重複)
- 意向部門(不可重複,最多5個)
興趣標籤(不可重複最多8個)
部門:
- 活動時間(設定最大為12個,且同一天的不同時間段不能重疊,且根據實際情況,時間不能是晚上10點後到第二天早上8點之間,活動時間為2小時)
- 部門人數限制(10-15之間)
- 部門編號(不可重複)
- 興趣標籤(因為一個部門主要比較專業,所以興趣標籤定為不超過3個)
原理:通過不斷的迴圈,給學生和部門的結構體陣列賦值,其中因為要模擬隨機性,所以大量用到了隨機數的演算法,除了學生學號和部門編號,其他都是隨機函式組合出來的。說是隨機,但是同一個學生或部門裡的一些資訊也不能重複,為了避免這個情況,就要給之前隨機出的結果做統計,不能重複,具體實現就是把之前的結果送進陣列裡然後每生成一次就查重一次。最後輸出的時候,用Json的格式進行輸出。
核心程式碼:
int random_num(int a, int b)//產生 [a,b]的隨機數
{
int rander;
rander = (rand() % (b - a + 1)) + a;
return rander;
}
for (int j = 0; j<a; j++)//產生興趣標籤
{
int b;
b = random_num(1, 11);
for (int x = 0; x<j; x++)//興趣標籤不能重複
{
if (num[x] == b)
{
b = random_num(1, 11);
x = 0;
}
}
num[j] = b;
stu[i].tags[j] = ttags[b];
}
輸出文字示例:https://github.com/n9705/Dep-Stu/blob/master/project/input_data.txt
學生輸出示例:
部門輸出示例:
不足:
- 空閒時間因為隨機,雖然當天的時間段不會重複,但是因為星期幾是隨機出來的,所以星期的排列並不是按照從小到大的順序排列,而是隨機排列的。
- 因為沒有給興趣標籤歸類,所以給部門匹配出的興趣標籤會很雜,比如匹配給一個部門加上了游泳和電腦這兩個標籤,就會感覺這部門不太正經,後期優化下。
生成資料用了C++輸出,然後自己加上格式,並沒有用Json的庫輸出,在但是還是在json_CN上校驗通過,輸出了正確的Json格式。
三、資料建模及匹配程式的思路及實現方式
資料建模:這部分主要我負責。從生成輸入資料的txt中用Json把資料解析出來然後裝進部門和學生的結構體陣列裡。
核心程式碼:
ifstream ifs;
ifs.open("input_data.txt");
assert(ifs.is_open());
Json::Reader reader;
Json::Value root;
if (!reader.parse(ifs, root, false))
{
return -1;
}
for (int i = 0; i < 300; i++)//給學生結構體陣列賦值
{
int size;
size = root["students"][i]["freetime"].size();
for (int j = 0; j < size; j++)//給空閒時間賦值
{
stu[i].free_time[j] = root["students"][i]["freetime"][j].asString();
}
stu[i].student_no = root["students"][i]["student_no"].asString();//學號賦值
size = root["students"][i]["applications_department"].size();
for (int j = 0; j < size; j++)//給意向部門賦值
{
stu[i].applications_department[j] = root["students"][i]["applications_department"][j].asString();
}
size = root["students"][i]["tags"].size();
for (int j = 0; j < size; j++)//給興趣標籤賦值
{
stu[i].tags[j] = root["students"][i]["tags"][j].asString();
}
}
匹配程式的思路:這部分主要由偉根負責。先按照學生的意向部門匹配,當部門編號匹配時再進行判斷學生的freetime和部門的event schedules是否滿足條件,條件為部門某天的活動時間範圍小於學生的當天的空閒時間,如果滿足,再判斷興趣標籤是否有至少一個符合意向部門的興趣標籤,如果有,再判斷部門收的人數是否已經達到member_limit,如果沒有,則把這個人放入這個部門,然後把該學生的標誌修改為已加入。
原理圖:
核心程式碼:
void application(int num)
{
for(int i=0;i<5;i++) //至多5個意向部門
{
for(int j=0;j<20;j++) //至多20個部門
{
int count=0; //計數變數
if(stu[num].applications_department[i]==dep[j].department_no) //第num個學生的第i個意向部門編號匹配到相應部門
{
set_student(num); //對該學生的freetime進行處理
set_department(j); //對該部門的event_schedule進行處理
for(int stu_time_count=0;stu_time_count<12;stu_time_count++) //至多12個空閒時間段
{
for(int dep_time_count=0;dep_time_count<12;dep_time_count++ ) //至多12個活動時間段
{
if(str1[stu_time_count].compare(str4[dep_time_count])==0) //匹配星期幾
{
if(str2[stu_time_count].compare(str5[dep_time_count])>=0&&str3[stu_time_count].compare(str6[dep_time_count])<0) //時間段比較
{
dep[j].save[count] = stu[num].student_no; //滿足條件就將該學生的學號存入對應的陣列
count++; //計數加一
if(count>dep[j].member_limit) continue;
}
}
}
}
}
}
}
}
四、 程式碼規範
1、 大括號一定要單獨一行
2、 每個函式都要有註釋,解釋其功能
3、 定義一個陣列或者變數時,要給出註釋說明其功能
五、 結果評估
輸出的unlucky_student人數比較多,大概一百八左右,原因是匹配程式的選擇條件比較簡單,先是意向部門編號匹配然後再是時間匹配,而且是由於for語句迴圈的問題,就較為簡單的輸出該學生被一個部門入取後不再被其他部門入取。
六、 結對感受
這次作業感覺完成的不是很好,主要是因為留給作業的時間太少。由於國慶假期出門旅遊,一號出去六號才回來,累得半死七號睡了一天,導致工期嚴重拖後。。八號才正式開始作業,感覺很對不起自己的隊友,是我拖累他了。緊趕慢趕加班熬夜趕才完成了作業的大概,還有很多需要完善的。。真的很想早點回來趕作業,可是無奈票是早就買好的,沒法改,花了錢在外面又不能不玩盡興。。唉,導致作業很趕,自己累也拖累隊友,不說了,都是淚。
這次作業給我最大的收益就是了解了Json這種輕量級的資料交換格式。對程式碼的輸出標準格式有了更深刻的認識,並且掌握了json的資料解析轉化,還有熟悉了隨機數的用法並且如何在一個給定的範圍隨機且不重複。
結對的感受,最大的就是兩個人程式碼風格的差異,所以要制定程式碼規範。還有遇到問題一定要制定計劃,及時溝通,主動聯絡,不然可能會導致對對方的進度有點不瞭解且合併程式碼的時候會因為雙方做的介面或者是變數設定不一樣導致各種問題,這也僅僅是兩個人的小團隊,如果是多個人,那會更麻煩,所以學好軟體工程是很重要的。還有就是,以後的作業和娛樂一定要安排好= =不能像這次一樣這麼趕了。