一、結對成員
- 031502332 汪志彬
- 031502315 李芳凱
二、專案github地址
三、資料生成原理與考慮因素
- 我們生成的一組資料:資料
(為了能比較直觀,設定學生數為30,部門數為5;可通過修改程式碼引數,改變學生數量和部門數量) - 資料生成原理:
- 學生資料:
- 學號(student_no):按順序生成。以“031502”開頭,從“001”開始依次增大
- 空閒時間(free_time):從週一到週日,通過隨機數(0或1)判斷當天是否產生空閒時間,產生則生成時間字串加入時間列表;為滿足空閒時間大於兩個,若最終生成的列表小於等於二,則重新生成
- 申報部門(applications_department):先生成一個[1,5]之間的整數作為申請數量。然後隨機生成一個數字對應部門的數字編號(判斷是否重複生成,達到數量後退出)
- 標籤(tags):將標籤設定為一個列舉型別,遍歷列舉物件,通過隨機數(0或1),判斷是否包含該標籤,若包含則加入該生標籤列表;若最終生成的列表小於等於二,則重新生成
- 部門資料:
- 部門號(department_no):按順序生成。以“D”開頭,從“01”開始依次增大
- 活動時間(event_schedules):與學生空閒時間生成方式相同
- 標籤(tags):與學生的標籤生成方式相同
- 人數限制(member_limit):採用隨機數生成函式生成[10,15]之間的整數
- 學生資料:
- 考慮因素:此生成程式最主要的特點是考慮到了部門的熱門程度(根據二八法則:%80的人選擇%20的部門)。將熱門的部門權重設定得大一點(實現方式是給比較熱門的部門分配比較多個的數字,eg:若有五個部門,生成隨機數字範圍設定為[1,15],部門1分配[1,8],部門2分配[9,11],依此),部門權重可通過修改程式碼進行設定。其它考慮的因素就是活動時間不能太早,最早從早上8點開始,最晚24點結束(好像還是有點晚)。
四、資料建模及匹配程式的思路及實現方式
- 資料建模
本次作業遇到的第一個難點就是如何從json格式的txt檔案中提取資料。最後通過搜尋發現有一個比較好用的的外部jar包(gson2.7),並學習了gson包的使用,有了這個工具讀取和輸出都顯得比較簡單了。資料組織方式和json中大體相似。如下- Department
- department_no:部門編號
- List event_schedules:部門活動時間,是一個String型別列表
- List tags:部門標籤,是一個String型別列表
- menber_limit:一個int型別,範圍在[10,15]之間的整數
- isempty:bool型別,判斷部門是否為空
- List member:是一個String型別的列表,儲存納入部門的學生學號
- Student
- student_no:學生編號
- application_departments:所申請的部門列表,是一個String型別列表
- List tags:學生標籤,是一個String型別列表
- List free_time:部門標籤,是一個String型別列表
- isadmitted:bool型別,判斷是否有被錄取
- Department
- 匹配程式
思路
具體的思路比較簡單。站在部門的角度來選擇學生,即每個部門依次去遍歷學生列表,總共兩輪,第一輪只錄取沒被其它部門錄取的學生,第二輪則是符合要求即錄取原因如下:
1、從頭到尾遍歷學生列表會對學號靠後的學生不公平,只錄取未被錄取的學生可以提高後面同學被錄取的機率(對後面的學生比較不公平)
2、 部門正常也希望所錄取的部員所加入部門儘可能少,這樣才能在部門活動中投入較多時間- 第一次遍歷納新的步驟如下
1.若該學生尚未加入任何部門,則執行下一步。否則選取下一位學生,執行1
2.若學生的空閒時間是否與部門活動時間匹配,若有執行下一步。否則從學生列表裡選取下一位,執行1
3.若學生有申請該部門,則執行下一步。否則從學生列表裡選取下一位,執行1
4.若該生標籤與部門匹配,則納入該生。從學生列表裡選取下一位,執行1 - 第二次遍歷納新步驟與第一次大體相同,但去除了步驟1,即第二輪符合條件即錄取,不管該生是否已加入部門
- 第一次遍歷納新的步驟如下
- 實現方式
// 開始匹配,由部門招人,分兩次,第一次招人優先招收未加入其它部門的人 for (ExDepartment exdepartment : ed) { for (ExStudent exstudent : es) { if(exstudent.isAdmitted()) continue; if (isMatch(exdepartment, exstudent)) { admitted(exdepartment, exstudent); } } } //第二次招人,符合要求即招入 for (ExDepartment exdepartment : ed) { for (ExStudent exstudent : es) { if(exdepartment.getMembers().contains(exstudent)) continue; if (isMatch(exdepartment, exstudent)) { admitted(exdepartment, exstudent); } }
private static boolean isMatch(ExDepartment exdepartment, ExStudent exstudent) { // TODO Auto-generated method stub if (timematch(exdepartment, exstudent)) { for (String apt : exstudent.getApplication_department()) { if (apt.equals(exdepartment.getDepartment_no())) { return tagMatch(exdepartment, exstudent); } } } return false; }
五、所遵循的程式碼規範(簡單舉例)
六、結果評估
- 最終使用作業釋出部落格裡面的input_data.txt的檔案進行評測。
- 評測結果:
未被錄取學生數:109
未錄取學生的部門數:0 - 分析:最終獲得的結果是大部分學生都能找到部門加入,大部分部門都能錄取到一定的人數(10人以上),覺得應該算是錄取率比較高的一種演算法,主要優點也是能讓更多人蔘與到部門活動中取。但是這種演算法不足也非常明顯,主要有以下兩點
- 對於學號靠後的學生較為不公平(雖然已經儘量避免)
- 部門與學生之間的匹配較為寬鬆,即學生只要有填報該部門,至少符合有一個空閒時間與部門活動時間匹配,至少有一個標籤與部門標籤匹配,就有比較大可能被錄用。這可能會導致部門因為人數限制沒有錄取到更合適的人(匹配程度更高的人)。
七、心得體會
- 個人收穫:通過這次的結對作業,我開始接觸Java包的使用,更加深刻地理解了Java的一些基礎知識。這次因為國慶放假,我和我的夥伴都回家了,所以也沒辦法坐在一起敲程式碼。程式碼主要是芳凱打的,只有結構佈局啊是我們一起構想的。感覺我這次沒有很參與到這次作業中,所以也沒有很大的收穫,但是沒辦法畢竟自己沒有投入很多時間。謝謝芳凱的辛勤!
- 結對感受:芳凱是我同班同學,平時就是非常不錯的一個人!在結對作業的兩次合作中,他體現了他的知識水平和程式碼能力,特別想提的一點是,芳凱這人性格好!並沒有因為我水平比較不好而心存抱怨,反而是對於我不懂的地方悉心耐心地指導我,還告訴一些學習Java的途徑,謝謝他!