PAT(A) - 1141. PAT Ranking of Institutions (25)

28 篇文章 0 订阅
4 篇文章 0 订阅

1141. PAT Ranking of Institutions (25)

时间限制
500 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

After each PAT, the PAT Center will announce the ranking of institutions based on their students' performances. Now you are asked to generate the ranklist.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (<=105), which is the number of testees. Then N lines follow, each gives the information of a testee in the following format:

ID Score School

where "ID" is a string of 6 characters with the first one representing the test level: "B" stands for the basic level, "A" the advanced level and "T" the top level; "Score" is an integer in [0, 100]; and "School" is the institution code which is a string of no more than 6 English letters (case insensitive). Note: it is guaranteed that "ID" is unique for each testee.

Output Specification:

For each case, first print in a line the total number of institutions. Then output the ranklist of institutions in nondecreasing order of their ranks in the following format:

Rank School TWS Ns

where "Rank" is the rank (start from 1) of the institution; "School" is the institution code (all in lower case); "TWS" is the total weighted score which is defined to be the integer part of "ScoreB/1.5 + ScoreA + ScoreT*1.5", where "ScoreX" is the total score of the testees belong to this institution on level X; and "Ns" is the total number of testees who belong to this institution.

The institutions are ranked according to their TWS. If there is a tie, the institutions are supposed to have the same rank, and they shall be printed in ascending order of Ns. If there is still a tie, they shall be printed in alphabetical order of their codes.

Sample Input:
10
A57908 85 Au
B57908 54 LanX
A37487 60 au
T28374 67 CMU
T32486 24 hypu
A66734 92 cmu
B76378 71 AU
A47780 45 lanx
A72809 100 pku
A03274 45 hypu
Sample Output:
5
1 cmu 192 2
1 au 192 3
3 pku 100 1
4 hypu 81 2
4 lanx 81 2

和乙级的 1085. PAT单位排行 (25) 是一样的。

本来是一道水题,可是又变成优化题,难怪通过率挺低的。

题意就是PAT每次考试完,姥姥在微博发的每个学校的成绩排行,现在让你模拟这个过程。总体考查多标尺排序和STL。

大概有这么三种做法:

方案一:定义10000大小的数组node,用来保存每个学校的信息。然后用map保存每个学校对应的id,id是int类型的,就是node的下标。然后用一个全局变量index记录有几个学校,最后排序sort(node, node + index, cmp)就行了。详情看代码:

#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <vector>

#define MAX 100000 + 10

using namespace std;

map<string, int> mpInt;
map<int, string> mpStr;

typedef struct Node {
    Node() { school = score = cnt = 0; }
    int school;
    int score;
    int cnt;
} Node;

Node node[MAX];
int index = 0;

int cmp( Node a, Node b ) {
    if( a.score != b.score ) return a.score > b.score;
    if( a.cnt != b.cnt ) return a.cnt < b.cnt;
    return mpStr[a.school] < mpStr[b.school];
}

int main() {
    int n;
    scanf( "%d", &n );

    string id, school;
    int score;
    for( int i = 0; i < n; i++ ) {
        cin >> id >> score >> school;
        // 学校名转成小写
        for( int j = 0; j < school.size(); j++ ) {
            if( school[j] >= 'A' && school[j] <= 'Z' ) school[j] = school[j] + 32;
        }
        // 计算转换后的分数
        switch( id[0] ) {
            case 'B': score = score * 1.0 / 1.5; break;
            case 'A': break;
            case 'T': score = score * 1.0 * 1.5; break;
        }

        if( !mpInt.count( school ) ) {
            mpInt[school] = index;
            mpStr[index] = school;
            node[index].school = index;
            node[index].cnt++;
            node[index].score = node[index].score + (int)score;
            index++;
        }
        else {
            int cur = mpInt[school];
            node[cur].cnt++;
            node[cur].score = node[cur].score + (int)score;
        }
    }

    sort( node, node + index, cmp );

    printf( "%d\n", index );
    int pre = -1;
    int cur;
    for( int i = 0; i < index; i++ ) {
        if( pre == -1 ) cur = i + 1;
        else if( pre != node[i].score ) cur = i + 1;
        pre = node[i].score;
        printf( "%d %s %d %d\n", cur, mpStr[node[i].school].c_str(), node[i].score, node[i].cnt );
    }
    return 0;
}

然后就超时了。。因为我们用map的时候,定义的类型是map<string, int>。string比char*要慢,小数据规模没啥效果,数据量一大就超时了。所以我们优化的时候就用map<char*, int>。但如果map的key用char*就很烦了,一般也不这么做。具体key为char*的坑如何解决看这个

https://blog.csdn.net/zark721/article/details/63685919

另外还有一个地方需要注意,map<char*, int> 中的key我定义的是学校的字符串,读输入的时候不能把char school[7]放在main函数里,因为要读n次数据,每次都会把school的值刷新一遍,这样的话map去找每次找的都是同一个值,我们应该定义一个school[10000][7],或者定义char* school,每次malloc分配内存(我也不知道该怎么解释,凑合着理解吧),具体可以看我程序。根据这个思路实现第二个做法。

方案二:使用map<char*, int>

#include <cstdio>
#include <map>
#include <cstring>
#include <algorithm>
#include <vector>

#define MAX 100000 + 10

using namespace std;

typedef struct Node {
    Node() { score = cnt = 0; }
    char school[7];
    double score;
    int cnt;
} Node;

Node node[MAX];

struct ptrCmp {
    bool operator()( const char * s1, const char * s2 ) const {
        return strcmp( s1, s2 ) < 0;
    }
};

map<char*, int, ptrCmp> mp;
int Index = 0;

int cmp( Node a, Node b ) {
    if( (int)a.score != (int)b.score ) return (int)a.score > (int)b.score;
    if( a.cnt != b.cnt ) return a.cnt < b.cnt;
    return strcmp( a.school, b.school ) < 0 ? 1 : 0;
}

//char school[MAX][7];
int main() {
    int n;
    scanf( "%d", &n );

    char id[7];
    char* school;
    double score;
    for( int i = 0; i < n; i++ ) {
        school = (char*)malloc( sizeof( char ) * 7 );
        scanf( "%s %lf %s", id, &score, school );
        //printf( "%s %s\n", id, school );
        // 学校名转成小写
        for( int j = 0; j < strlen( school ); j++ ) {
            if( school[j] >= 'A' && school[j] <= 'Z' ) school[j] = school[j] + 32;
        }
        // 计算转换后的分数
        switch( id[0] ) {
            case 'B': score = score / 1.5; break;
            case 'A': break;
            case 'T': score = score * 1.5; break;
        }

        if( !mp.count( school ) ) {
            mp[school] = Index;
            strcpy( node[Index].school, school );
            node[Index].cnt++;
            node[Index].score = node[Index].score + score;
            Index++;
        }
        else {
            int cur = mp[school];
            node[cur].cnt++;
            node[cur].score = node[cur].score + score;
        }
    }

    sort( node, node + Index, cmp );

    printf( "%d\n", Index );
    int pre = -1;
    int cur;
    for( int i = 0; i < Index; i++ ) {
        if( pre == -1 ) cur = i + 1;
        else if( pre != (int)node[i].score ) cur = i + 1;
        pre = (int)node[i].score;
        printf( "%d %s %d %d\n", cur, node[i].school, (int)node[i].score, node[i].cnt );
    }
    return 0;
}

然后就AC了,哈哈哈哈,速度超级快。

方案三:见网上大部分AC的是用两个map<string, int>,一个统计人数,另一个统计学校的加权总分。然后遍历map,把每个学校的信息push_back到vector中,然后再排序,不太明白这么做为什么会快(相对于方案一),但是这么做能AC。具体实现看下面代码:

#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#include <vector>

#define MAX 100000 + 10

using namespace std;

typedef struct Node {
    Node() { score = cnt = 0; }
    string school;
    int score;
    int cnt;
} Node;

vector<Node> vec;
map<string, int> mpCnt;
map<string, double> mpScore;

int cmp( Node a, Node b ) {
    if( a.score != b.score ) return a.score > b.score;
    if( a.cnt != b.cnt ) return a.cnt < b.cnt;
    return a.school < b.school;
}

int main() {
    int n;
    scanf( "%d", &n );

    string id, school;
    double score;
    for( int i = 0; i < n; i++ ) {
        cin >> id >> score >> school;
        // 学校名转成小写
        for( int j = 0; j < school.size(); j++ ) {
            if( school[j] >= 'A' && school[j] <= 'Z' ) school[j] = school[j] + 32;
        }
        // 计算转换后的分数
        switch( id[0] ) {
            case 'B': score = score / 1.5; break;
            case 'A': break;
            case 'T': score = score * 1.5; break;
        }

        if( mpCnt.count( school ) ) {
            mpCnt[school]++;
            mpScore[school] = mpScore[school] + score;
        }
        else {
            mpCnt[school] = 1;
            mpScore[school] = score;
        }
    }

    Node t;
    for( map<string, int>::iterator it = mpCnt.begin(); it != mpCnt.end(); it++ ) {
        t.school = it->first;
        t.cnt = it->second;
        t.score = (int)mpScore[it->first];
        vec.push_back( t );
    }

    sort( vec.begin(), vec.end(), cmp );

    int len = vec.size();
    printf( "%d\n", len );
    int pre = -1;
    int cur;
    for( int i = 0; i < len; i++ ) {
        if( pre == -1 ) cur = i + 1;
        else if( pre != vec[i].score ) cur = i + 1;
        pre = vec[i].score;
        printf( "%d %s %d %d\n", cur, vec[i].school.c_str(), vec[i].score, vec[i].cnt );
    }
    return 0;
}

能AC,但险些超时,运气不好说不定最后一个测试点就GG了。。优点是内存占用小。

方案四(我自己临时想的):对于方案一,如果我们不知道map<char*, int>怎么用,可能就放弃用map的想法了。由于题目中说学校是一个不超过7个长度的字符串,如果我们自己写一个hash函数,然后用char*读输入,说不定也能AC,但具体怎么实现这个哈希函数我没想好。或者用unordered_map说不定也能AC,但需要支持C++11,我没试PAT的编译器是否支持。


另外此题还有一个坑:题目中说最后学校的加权和是整数,我们程序计算的时候先用double,最后输出的时候强转成int。当计算N个学生成绩的时候,因为要*1.5或/1.5,就产生小数了,如果你每次都把double转成int,最后精度就错误了,导致最后一个测试点答案错误,这个就很坑了。。

希望对路过的同学有帮助

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值