PAT甲级A11411141 PAT Ranking of Institutions超时问题

13 篇文章 1 订阅
12 篇文章 0 订阅

原题链接添加链接描述
思索一番,该题还是写一篇文章,因为对于我帮助挺大的,其实也是困扰了半天。

直观思路

本题,最直观的思路是,使用unordered_map < string,double > 建立学校到成绩的映射,使用unordered_map < string,int > cnt建立从学校到人数的映射。使用vector < string > total 来存储下所有出现过的学校。
代码如下

#include <bits/stdc++.h>

using namespace std;

vector<string> total;
unordered_map<string,double> tws;
unordered_map<string,int> cnt;

bool cmp(string &a,string &b){
    if((int)tws[a] != (int)tws[b]) return (int)tws[a] > (int)tws[b];
    else if(cnt[a] != cnt[b]) return cnt[a] < cnt[b];
    else return a < b;
}

int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        char id[7];
        double grade;
        string name;
        scanf("%s%lf",id,&grade);
        cin>>name;
        transform(name.begin(),name.end(),name.begin(),::tolower);
        if(!cnt[name]) total.push_back(name);
        cnt[name]++;
        if(id[0] == 'B') grade /= 1.5;
        else if(id[0] == 'T') grade *= 1.5;
        tws[name]+=grade;
    }

    sort(total.begin(),total.end(),cmp);
    cout<<total.size()<<endl;
    int r = 1;
    for(int i=0;i<total.size();i++){
        if(i && (int)tws[total[i]] != (int)tws[total[i-1]] ) r = i + 1;
        cout<<r<<' '<<total[i]<<' '<<(int)tws[total[i]]<<' '<<cnt[total[i]]<<endl;
    }

    return 0;
}

提交试试
在这里插入图片描述
可以看到,测试点4和5超时。代码中能用scanf和printf的地方,都使用了scanf和printf,还是超时,只能是这个思路是不行的。但是这个思路是非常直观的,只不过后两个测试点数据量太大,不适用。

另谋他路

另外的思路是,因为题目告知n最大为100000,也就是,最多有100000所学校,这样,就使用结构体school来存放学校信息,包括,该学校人数、tws,以及学校名字。并且开辟一个大小为100000大小的结构体数组,这样,最重要的是要建立从学校到数组下标的映射,即unordered_map < string,int > name_id,当读入一个数据时,将学校中的大写字母变成小写字母之后,查询一下是否已经有了从学校到结构体数组的映射,如果已经有了映射,则直接在映射结果的结构体上修改数据,否则,建立映射,添加数据。

#include <bits/stdc++.h>

using namespace std;

struct school{
    int cnt;
    double tws;
    string name;
    school(){
        cnt = 0;
        tws = 0.0;
    }
    bool operator < (const school &b) const{
        if((int)tws != (int)b.tws) return (int)tws > (int)b.tws;
        else if(cnt != b.cnt) return cnt < b.cnt;
        else return name < b.name;
    }
};

int number = 0;
const int maxn = 1e5+1;
vector<school> total(maxn);
unordered_map<string,bool> have_id;
unordered_map<string,int> name_id;

int main()
{
    int n;
    cin>>n;
    double grade;
    char id[7];
    string name;
    for(int i=0;i<n;i++){
        scanf("%s%lf",id,&grade);
        cin>>name;
        transform(name.begin(),name.end(),name.begin(),::tolower);
        if(!have_id[name]){
            name_id[name] = number++;
            have_id[name] = true;
        }
        int cur = name_id[name];//映射到已经开辟了空间的结构体数组中去
                                //这远比使用unorderde_map遇到一个string就开辟一个空间,节省时间
        if(id[0] == 'T') grade *= 1.5;
        else if(id[0] == 'B') grade /= 1.5;
        total[cur].cnt++;
        total[cur].tws += grade;
        total[cur].name = name;
    }
    sort(total.begin(),total.begin()+number);
    cout<<number<<endl;
    int r = 1;
    for(int i=0;i<number;i++){
        if(i&&((int)total[i].tws != (int)total[i-1].tws)) r = i + 1;
        cout<<r<<' '<<total[i].name<<' '<<(int)total[i].tws<<' '<<total[i].cnt<<endl;
    }
    return 0;
}

使用这个思路,再看一下提交结果
在这里插入图片描述

总结

可以看到这次,4、5测试点是没有超时,并且,前4个测试点的用时与上一种思路的用时差不多,都是一个数量级,也就是说,当数据量较少时,可以使用unordered_map来建立映射,但是当数据量巨大时,使用unordered_map < string,XXX > 来建立从string到其他类型XXX的数据映射,是比较费时的,这也与本题相关,可能后两个测试点,不断的有新的学校,在第一种思路中,所有从string到其他数据类型的映射都要不断地插入新的数据,这也就使得需要的内存空间确实是按需开辟,但是,在卡时间的oj上,这涉及到反复插入数据,尤其key为string,肯定比普通的int类型更费时间。
在第二种思路中,已经提前建立了结构体数组,只需要将学校姓名name映射到结构体数组的对应位置,进行数据修改即可,这个时间复杂度是O(1),肯定要比来一个尚未出现的数据就从新插入要节省时间。

本题告诉我,使用unordered_map<string,XXXX> 确实是非常方便
但是,其中的映射是一个一个的进行插入的
数据量巨大时,是相当耗时间的。数据量不大时,可以这么做
而最好是,建立string->int的映射。
因为数组是已经开辟好的,只是往里面进行填充,而不是用到了才开辟空间

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值