10-排序5 PAT Judge(1075) 通过所有测试点

PAT Judge

1075 PAT Judge

#include <iostream>
#include <string>
#include <iomanip>
#define MAXN 10000
#define MAXK 5
#define MAXM 100000
using namespace std;

typedef struct user *User;
struct user {
    int id;
    int score[MAXK];
    int total;
    int numOfPer;
    bool isShown;
    bool operator< (const user& t) const { // 重载关系运算符!
        if( total != t.total )  return total < t.total; // total小的在<左边
        if( numOfPer != t.numOfPer )    return numOfPer < t.numOfPer;
        return id > t.id;
    }
};
User Info[MAXN];

void print( User U, int K ) {
    cout << setw(5) << setfill('0') << U->id; 
    cout << " " << U->total << " ";
    for( int i = 0; i < K; i++ ) {
        if( U->score[i] == -2 ) cout << "-"; // -2则表示未提交过
        else if( U->score[i] == -1 )    cout << "0";
        else    cout << U->score[i];
        
        if( i != K-1 )  cout << " "; // 不是最后一个
        else    cout << endl;
    }
}

int main() {
    int N, K, M, pos, score, id;
    int full[MAXK];
    cin >> N >> K >> M;
    
    for( int i = 0; i < N; i++ ) { // 就算没有提交也要算一个用户!
        Info[i] = new user; // 重要!!
        Info[i]->id = i + 1;
        Info[i]->isShown = false;
        Info[i]->total = Info[i]->numOfPer = 0; // 初始化
        for( int j = 0; j < K; j++ )
            Info[i]->score[j] = -2; // 最小的成绩是-1
    }
    
    for( int i = 0; i < K; i++ )
        cin >> full[i];
    
    for( int i = 0; i < M; i++ ) {
        cin >> id >> pos >> score;
        id--;
        pos--;
        if( score > Info[id]->score[pos] ) // 更高的分数替代原来的分数
            Info[id]->score[pos] = score;
        if( score != -1 )   Info[id]->isShown = true; // 有一道过编译就显示
    }
    
    for( int i = 0; i < N; i++ )
        for( int j = 0; j < K; j++ )
            if( Info[i]->score[j] >= 0 ) {
                Info[i]->total += Info[i]->score[j];
                if( Info[i]->score[j] == full[j] )  Info[i]->numOfPer++;
            }
    
    int j;
    User Tmp;
    for ( int i = 1; i < N; i++ ) { // 插入排序
        Tmp = Info[i]; /* 取出未排序序列中的第一个元素 */
        for ( j = i; j > 0 && *Info[j-1] < *Tmp; j-- ) // 重载<
            Info[j] = Info[j-1]; /* 依次与已排序序列中元素比较并右移 */
        Info[j] = Tmp; /* 放进合适的位置 */
    }
    
    cout << "1 "; // 保证至少有一个人会被展示(如果所有人都不能被展示, 展示id为00001的成绩)
    print( Info[0], K );
    
    int rank = 1, num = 1, last_score = Info[0]->total;
    for( int i = 1; i < N; i++ ) // 考虑 全是-1而总分为0的用户 因为id更小排在 全是0而总分为0的用户 前面
        if( Info[i]->isShown ) {
            if( Info[i]->total != last_score ) { // 不能与[i-1]作比较, 它有可能不输出!!!
                rank += num;
                num = 1;
                last_score = Info[i]->total; // 不相等时更新
            }
            else    num++;
            cout << rank << " ";
            print( Info[i], K );
        }
}

乍一看不难,实际上各种细节会让人抓狂,死磕了一晚上加一上午...

在csdn上看了很多测试点分析,个人说几点吧

  1. -1代表提交过但未通过编译,-2代表未提交过,总分只加大于等于0的分数,不会加负分
  2. 原来有得分后面再提交-1是不会覆盖的,毕竟题目也说了取最高分
  3. 排序的时候最好重载一下比较方法,不管是运算符还是cmp,因为要考虑到同总分的可能有很多用户,我这里用的是插入排序,可能会跃迁不止一次
  4. 保证至少一个人的成绩会被展示(所有人都不符合展示条件时展示id为00001的成绩)
  5. 重复提交满分不要重复增加满分次数(通过只取更高分解决)
  6. rank也有一个小难点,要注意到并不是所有用户都会被展示,中间可能断层

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

低冷dl

喜欢您来~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值