第二次結對編程做業——畢設導師智能匹配

031402429張秀鋒 031402310洪志興git

項目連接:https://coding.net/u/dtewx/p/Pair-Programming-Work/git算法

要求內容:

編碼實現一個畢設導師的智能匹配的程序。提供輸入包括:30個老師(包含帶學生數的要求的上限,單個數值,在[0,8]內),100個學生(包含績點信息),每一個學生有5個導師志願(志願的導師能夠重複但不能空缺)。實現一個智能自動分配算法,根據輸入信息,輸出導師和學生間的匹配信息(一個學生只能有一個確認導師,一個導師能夠帶少於等於其要求的學生數的學生) 及 未被分配到學生的導師 和 未被導師選中的學生。 編程

問題分析:

此次的做業要求比較簡單,條件也比較少,只有輸入數據輸出結果,重點在於儘可能減小未被分配到的學生數量,但同時也應該知足一些要求,好比學生的績點排名、志願順序等,通過討論咱們肯定了下面幾個原則:學習

1.績點優先:績點較高的學生應該有優先權選擇導師
2.志願順序優先:優先考慮學生前面的志願
3.學生意願優先:只把學生分配給他志願中的導師,不強制分配測試

方法設計:

咱們討論的方法比較簡單,主要是排序的方法,根據對象有下面三種排序方式:編碼

1.按績點分配:把學生按績點從高到低排序,從第一個學生開始,依次考慮他的五個志願,若該志願的導師指望人數不爲零則將該學生分配給導師,不然不分配,輪到下一個學生,若五個志願都沒法分配,那麼這個學生被剩下。全部學生輪到事後結束。.net

2.按志願分配:先對學生的績點從大到小進行排序,而後進行5次循環:對全部學生的第i(i從1到5)志願按從績點高的開始分配(只看第i志願),第i志願導師限選人數已滿就跳過,放到下一次循環(第i+1志願),直到剩下的學生的全部志願導師都被選滿爲止。設計

3.按導師分配:選出有被選擇的導師,按導師被選人數從大到小排序並按這個順序進行:對每一個導師,先把選擇他的學生按志願排列,再對每級志願按績點排列,按這個順序把學生分配給導師直到限選人數滿了或者沒學生了,輪到下一個導師,全部導師輪到事後結束。code

上述的三種方法都各有特色,其中第一種方法強調績點,對於績點高的同窗頗有好處,但績點低的就很沒有優點,很容易落選;第二種方法綜合了學生的績點和志願順序,比前者均衡,績點越高志願越靠前越能選中;第三種從導師角度選擇,也比較均衡,就是導師的順序對結果影響較大,越靠前的導師越能選中學生,不過對導師排序彷佛不妥。最後咱們選擇了第二種方法,雖然並非最好的方法,不過也兼顧了績點和志願順序。對象

三種方法在學生扎堆選擇導師時落選的學生都會比較多,不過考慮到學生意願優先,在沒有強制分配的狀況下結果也是由學生本身選擇的,跟他們的選擇分佈有很大關係。

算法流程:

1.對學生按績點進行排序;
2.開始第i輪循環:只考慮第i志願,從績點最高的開始,若導師限選人數未滿,則將該學生分配給該導師,不然繼續下一個學生;
3.五輪循環結束後,輸出結果;(輸出格式爲:「導師號:學生號」,即每一個導師被分配到的學生以及已分配的學生數和未分配學生、導師的編號)

流程圖:

實現代碼:

定義結構體:

struct student{
int sno;
int cho[5];
double gpa;
bool chos;
};
 
struct teacher{
int tno;
int wnum;
int snum;
bool chos;
int stud[8];
};

生成隨機數據:

freopen("input.txt","w",stdout);
srand((int)time(0));
for(i=1;i<=snum;i++){
    printf("%d ",i);
    for(k=0;k<5;k++){
        j=1+(int)((float)tnum*rand()/(RAND_MAX+1.0));
        printf("%d ",j);
    }
        gpa=1+(float)((40.0*rand()/(RAND_MAX+1.0))/10);
        printf("%.2f ",gpa);    
}

讀取文件:

void readdata(student s[],teacher t[]){
int i,j;
freopen("input.txt","r",stdin);
for(i=0;i<snum;i++){
    scanf("%d",&s[i].sno);
    for(j=0;j<5;j++)
    scanf("%d",&s[i].cho[j]);
    scanf("%lf",&s[i].gpa);
    s[i].chos=false;
}
for(i=0;i<tnum;i++){
scanf("%d%d",&t[i].tno,&t[i].wnum);
t[i].snum=0;
t[i].chos=false;
}
fclose(stdin);
}

利用快排進行排序:

void sort(student s[],int l,int r){
int i,j;  
student x; 
if(l<r){
    i=l;  
    j=r;  
    x=s[i];  
    while(i<j){  
        while(i<j&&s[j].gpa>x.gpa)   
            j--; 
        if(i<j)   
            s[i++]=s[j];
        while(i<j&&s[i].gpa<x.gpa)   
            i++;
        if(i<j)
            s[j--]=s[i];
    }  
    s[i]=x;
    sort(s,l,i-1); 
    sort(s,i+1,r);
}
}

分配及輸出:

void fp(student s[],teacher t[]){
freopen("output.txt","w",stdout);
int i,j,x,k=0,h;
for(i=0;i<5;i++)
for(j=snum-1;j>=0;j--){
    x=match(t,s[j].cho[i]);
    if(s[j].chos==false&&t[x].wnum>0){
    s[j].chos=true;
    t[x].chos=true;
    t[x].wnum--;
    t[x].snum++;
    h=t[x].snum-1;
    t[x].stud[h]=s[j].sno;
    k++;
    }
    else continue;
}
printf("Result(Teacher: student):\n");
for(i=0;i<tnum;i++)
    if(t[i].chos==true){
        printf("%d:",t[i].tno);
        for(j=0;j<t[i].snum;j++)
            printf("%d ",t[i].stud[j]);
        printf("\n");
    }
printf("\nNumber of arranged students: %d\n",k);
printf("Unarranged students: ");
for(i=0;i<snum;i++)
if(s[i].chos==false)
printf("%d ",s[i].sno);
printf("\nUnarranged teachers: ");
for(i=0;i<tnum;i++)
if(t[i].chos==false)
printf("%d ",t[i].tno);
fclose(stdout);
}

算法評估

設s爲有被學生選擇的全部導師的指望人數之和,a爲學生總人數,b爲用算法實際完成分配的學生人數,若s>=a,則算法應儘可能使b接近或等於a;若s<a,則算法應儘量使b接近或等於s;用y=b/[min(a,s)]來表示算法的分配完成度。因爲實際狀況下s不小於a,因此用y=b/a來計算。

用隨機生成的數據進行了10次測試,每次都是100個學生和30個導師,測試結果以下:

能夠看到效果仍是能夠的,整體的中選率在90%以上。雖然隨機數的結果跟實際上的會有一些差異,但在學生選擇較爲平均的狀況下仍是能保證必定的中選率。另外因爲隨機數生成時不能保證導師指望人數和老是大於學生總數,結果也會有些誤差,形成中選率偏小。測試隨機數據只能用來作一個大概的參考,並不能很好地模擬實際狀況。總之,仍是要看實際的檢驗。

算法不足

咱們所用的算法規則很簡單,只是機械地按照排好的順序進行分配,沒有進行權重計算、動態分配,缺少靈活性,不能保證結果是最優的,另外對於一些狀況好比扎堆選擇不能有效的避免學生落選。

後續改進

雖然此次的要求中沒有導師對學生的選擇狀況,不過咱們能夠在代碼中把導師的選擇加入規則,當學生被導師接受時照常進行分配,當被拒絕時能夠直接排除。

建議分享

其實就是一些咱們結對合做過程當中遇到的一些小問題,而後想起《構建之法》中老師提到的幾個點:

一、一開始咱們的代碼中有中文的字符(提示或是註釋),在咱們傳送文件,另外一人接收後,中文字符就都亂碼了。多是環境不一樣的緣故,因此按照書中提到的「註釋(包括全部源代碼)應該只用ASCII字符,不要用中文或其餘特殊字符,不然會極大影響程序的可移植性。」因此,咱們就用蹩腳的英語寫了註釋,儘可能作到簡明扼要能讓人看懂。

二、第二點也是代碼風格的問題,由於曾經就遇到過,原本在實驗室寫的代碼,帶回打開後發現縮進變得很彆扭,有的長有的段,緣由是「tab鍵在不一樣的狀況下會顯示不一樣的長度,嚴重感染閱讀體驗。」因此,咱們就把全部的tab縮進替換成4個空格。

可能這是些小細節,卻值得咱們去吸取和學習。

結對感覺

zxf:通過第一次做業的幾回交流討論磨合,此次做業的討論比上次更像是在真正地討論問題了,更放得開大膽地講咱們的想法,隊友提出疑問而後再一塊兒想改進的方法。在討論過程當中咱們經常會錯意,沒有徹底弄清楚隊友的意思,更深刻的交流和討論,這應該也是進一步磨合的過程吧。咱們的默契還有提高的空間!

hzx:此次的做業中咱們採起了很簡單的方法來實現,只能說實現了「分配」,算不上是「智能」,雖然隨機數模擬的效果還行,我的感受並無很好地達到目標。咱們有進行過討論,不過沒有抓住重點,更多地在考慮一些實際的細節和特殊狀況,最後採用了簡單的方法,另外因爲我編程上比較渣,咱們動手也比較晚,結果就這樣了吧,總的來講還有不少能夠改進的地方。

相關文章
相關標籤/搜索