1. 程式人生 > >HDU 2093考試排名(結構體多關鍵字排序+字串處理)

HDU 2093考試排名(結構體多關鍵字排序+字串處理)

題目

Description
C++程式設計考試使用的實時提交系統,具有即時獲得成績排名的特點。它的功能是怎麼實現的呢?
我們做好了題目的解答,提交之後,要麼“AC”,要麼錯誤,不管怎樣錯法,總是給你記上一筆,表明你曾經有過一次錯誤提交,因而當你一旦提交該題“AC”後,就要與你算一算帳了,總共該題錯誤提交了幾回。雖然你在題數上,大步地躍上了一個臺階,但是在耗時上要攤上你共花去的時間。特別是,曾經有過的錯誤提交,每次都要攤上一定的單位時間分。這樣一來,你在做出的題數上,可能領先別人很多,但是,在做出同樣題數的人群中,你可能會在耗時上處於排名的劣勢。
例如:某次考試一共8題(A,B,C,D,E,F,G,H),每個人做的題都在對應的題號下有個數量標記,負數表示該學生在該題上有過的錯誤提交次數,但到現在還沒有AC,正數表示AC所耗的時間,如果正數a跟上一對括號,裡面有個整數b,那就表示該學生提交該題AC了,耗去了時間a,同時,曾經錯誤提交了b次,因此對於下述輸入資料:
這裡寫圖片描述

若每次錯誤提交的罰分為20分,則其排名從高到低應該是這樣的:
Josephus 5 376
John 4 284
Alice 4 352
Smith 3 167
Bob 2 325
Bush 0 0

Input
輸入資料的第一行是考試題數n(1≤n≤12)以及單位罰分數m(10≤m≤20),每行資料描述一個學生的使用者名稱(不多於10個字元的字串)以及對所有n道題的答題現狀,其描述採用問題描述中的數量標記的格式,見上面的表格,提交次數總是小於100,AC所耗時間總是小於1000。

Output
將這些學生的考試現狀,輸出一個實時排名。實時排名顯然先按AC題數的多少排,多的在前,再按時間分的多少排,少的在前,如果湊巧前兩者都相等,則按名字的字典序排,小的在前。每個學生佔一行,輸出名字(10個字元寬),做出的題數(2個字元寬,右對齊)和時間分(4個字元寬,右對齊)。名字、題數和時間分相互之間有一個空格

Sample Input

8 20
Smith -1 -16 8 0 0 120 39 0
John 116 -2 11 0 0 82 55(1) 0
Josephus 72(3) 126 10 -3 0 47 21(2) -2
Bush 0 -1 -8 0 0 0 0 0
Alice -2 67(2) 13 -1 0 133 79(1) -1
Bob 0 0 57(5) 0 0 168 -7 0

Sample Output

Josephus 5 376
John 4 284
Alice 4 352
Smith 3 167
Bob 2 325
Bush 0 0

題目大意

根據若干個學生的oj上n道題的提交資訊進行排名,題數多的名次高,題數相同時用時短的名次高,題數時間均相同時姓名字典序小的名次高。

分析

本題是到練排序及字串處理的好題。
按沒提交、沒通過、1A及有失敗次數的AC對各題資訊分類統計題數及時間,記錄到結構體陣列中,按要求進行多關鍵字排序。
值得注意的是:
1.結構體多關鍵字排序時cmp函式的寫法
2.由於輸入的學生數不定,小黑窗測試比較麻煩,最好用檔案輸入輸出測試,並要注意EOF也是一個字元,因此統計學生數時需將cnt-1
3.本題的輸出格式

程式碼

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define N 1010
using namespace std;
struct STU
{
    char name[12];
    int solve,time;
}stu[N];
bool cmp(struct STU a,struct STU b) //多關鍵字排序cmp
{
    return((a.solve>b.solve)||((a.solve==b.solve)&&(a.time<b.time))||((a.solve==b.solve)&&(a.time==b.time)&&strcmp(a.name,b.name)<0));
}
int main()
{
    int cnt,i,n,m,x,t;
    char ch[100];
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    scanf("%d%d",&n,&m);
    cnt=0;
    while (scanf("%s",stu[++cnt].name)!=EOF)
    {
        stu[cnt].solve=stu[cnt].time=0;
        for (i=1;i<=n;i++)
        {
            scanf("%s",ch);
            if (ch[0]=='0') continue;         ///沒提交
            if (ch[0]=='-') continue;         ///沒AC

            stu[cnt].solve++;
            x=0;t=0;
            if (!strstr(ch,"("))              ///1A的情況
            {
                while (ch[t])
                    x=x*10+ch[t++]-'0';
                stu[cnt].time+=x;
                continue;
            }

            while (ch[t]!='(')                 ///有失敗次數的AC
                x=x*10+ch[t++]-'0';
            stu[cnt].time+=x;
            x=0;t++;
            while (ch[t]!=')')
                x=x*10+ch[t++]-'0';
            stu[cnt].time+=x*m;
        }
    }
    cnt--;    ///除去檔案結束符
    sort(stu+1,stu+cnt+1,cmp);
    for (i=1;i<=cnt;i++)
        printf("%-10s %2d %4d\n",stu[i].name,stu[i].solve,stu[i].time);///注意輸出格式
    return 0;
}