【PAT甲级】1055 The World's Richest

Forbes magazine publishes every year its list of billionaires based on the annual ranking of the world's wealthiest people. Now you are supposed to simulate this job, but concentrate only on the people in a certain range of ages. That is, given the net worths of N people, you must find the M richest people in a given range of their ages.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers: N (≤10​5​​) - the total number of people, and K (≤10​3​​) - the number of queries. Then N lines follow, each contains the name (string of no more than 8 characters without space), age (integer in (0, 200]), and the net worth (integer in [−10​6​​,10​6​​]) of a person. Finally there are K lines of queries, each contains three positive integers: M (≤100) - the maximum number of outputs, and [AminAmax] which are the range of ages. All the numbers in a line are separated by a space.

Output Specification:

For each query, first print in a line Case #X: where X is the query number starting from 1. Then output the M richest people with their ages in the range [AminAmax]. Each person's information occupies a line, in the format

Name Age Net_Worth

The outputs must be in non-increasing order of the net worths. In case there are equal worths, it must be in non-decreasing order of the ages. If both worths and ages are the same, then the output must be in non-decreasing alphabetical order of the names. It is guaranteed that there is no two persons share all the same of the three pieces of information. In case no one is found, output None.

Sample Input:

12 4
Zoe_Bill 35 2333
Bob_Volk 24 5888
Anny_Cin 95 999999
Williams 30 -22
Cindy 76 76000
Alice 18 88888
Joe_Mike 32 3222
Michael 5 300000
Rosemary 40 5888
Dobby 24 5888
Billy 24 5888
Nobody 5 0
4 15 45
4 30 35
4 5 95
1 45 50

Sample Output:

Case #1:
Alice 18 88888
Billy 24 5888
Bob_Volk 24 5888
Dobby 24 5888
Case #2:
Joe_Mike 32 3222
Zoe_Bill 35 2333
Williams 30 -22
Case #3:
Anny_Cin 95 999999
Michael 5 300000
Alice 18 88888
Cindy 76 76000
Case #4:
None

题意理解

输入给出n个人的姓名、年龄和财富,然后进行k次查询,每次查询某个年龄段最富有的m个人,按照财富从大到小输出,如果财富相同则按照年龄从小到大输出,如果财富年龄都相同则按姓名字母序输出,如果没有符合要求的人输出None,如果符合要求的人数小于查询人数,则输出所有符合要求的人。

个人思路

这题是排序题的应用,一开始以为很简单,但是由于数据比较大,时间限制比较小,经过了三次大改动才AC。

第一次想法:先将所有的人按照年龄从小到大排序,然后进行查询时遍历按照年龄排序后的数组,找到年龄区间,将这个区间内的所有人再放入另外一个数组中按照题目的要求进行排序,然后输出。这种思路大大超时,有两个样例都TLE了。

第二次的想法:建立205个动态数组,下标代表年龄,在输入n个人时就将每个人存入对应年龄的动态数组中,然后查询时直接将对应年龄的动态数组合并然后排序输出。这种思路比第一种快,但是还有一个样例TLE了。

代码如下:

#include <cstdio>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#define ll long long
#define eps 1e-8
#define INF 0x7FFFFFFF

using namespace std;

struct People{
    string name;
    int age, money;
};

bool cmp_query(People p1, People p2) {
    if (p1.money != p2.money) return p1.money > p2.money;
    else if (p1.age != p2.age) return p1.age < p2.age;
    else return p1.name < p2.name;
}

int main() {
    int n, k;
    vector<People> ages[205];
    cin >> n >> k;
    for (int i = 0; i < n; i ++) {
        People tmp;
        cin >> tmp.name >> tmp.age >> tmp.money;
        ages[tmp.age].push_back(tmp);
    }
    for (int i = 0; i < k; i ++) {
        int num, amin, amax, cnt = 0;
        cin >> num >> amin >> amax;
        vector<People> query_list;
        for (int a = amin; a <= amax; a ++) {
            for (vector<People>::iterator it = ages[a].begin(); it != ages[a].end(); it ++) {
                query_list.push_back(*it);
                cnt ++;
            }
        }
        cout << "Case #" << i+1 << ":" << endl;
        if (cnt == 0) {
            cout << "None" << endl;
        }
        else {
            sort(query_list.begin(), query_list.end(), cmp_query);
            num = min(num, cnt);
            for (int j = 0; j < num; j ++) {
                cout << query_list[j].name << " " << query_list[j].age << " " << query_list[j].money << endl;
            }
        }
    }
    return 0;
}

第三次的想法:之前两个思路都TLE后,我有点没头绪了,想不出为什么T,然后就再次求助了柳神的博客https://blog.csdn.net/liuchuo/article/details/52225204,然后知道了由于查询数量m的最大值100和总人数的最大值10^5相差太大,如果按照第二种思路,有可能每次都查询很大的年龄区间就有很多人,然后在进行排序的过程虽然是快排,复杂度为O(nlogn),但是查询次数还有1000次呢,所以还是有可能超时的。

所以我参考了柳神的思路后按照她的想法修改了自己的代码,在输入n个人的信息后将所有人一起按照题目要求排序并存在数组中,然后设定一个结构体数组query_all存放进行查询的人的信息,同时设立一个整型数组age_cnt[205]存放某个年龄要加入查询列表的人的数量,因为最多查询100人,所以当某个年龄的人数量大于100后就不再将这个年龄的加入query_all了。然后进行k次查询时直接遍历query_all将满足年龄条件的人加入结果数组最后输出即可。

【这里还有一个坑】

当我按照柳神的思路实现代码后,发现还是会TLE,检查代码后发现所有的输入输出我都是用cout和cin流实现的,突然想起刷乙级题的时候也遇上过因为cout和cin超时的题,然后改成了printf和scanf后就过了。

实现代码如下:

#include <cstdio>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#define ll long long
#define eps 1e-8
#define INF 0x7FFFFFFF

using namespace std;

struct People{
    char name[10];
    int age, money;
};

bool cmp(People p1, People p2) {
    if (p1.money != p2.money) return p1.money > p2.money;
    else if (p1.age != p2.age) return p1.age < p2.age;
    else return (strcmp(p1.name, p2.name) < 0);
}

int main() {
    // 输入
    int n, k;
    vector<People> all_people;
    cin >> n >> k;
    for (int i = 0; i < n; i ++) {
        People tmp;
        scanf("%s %d %d",tmp.name, &tmp.age, &tmp.money);
        all_people.push_back(tmp);
    }
    // 将所有人进行排序
    sort(all_people.begin(), all_people.end(), cmp);
    // 选出每个年龄段的前100人
    vector<People> query_all;
    int age_num[205] = {0};
    for (int i = 0; i < n; i ++) {
        People tmp = all_people[i];
        if (age_num[tmp.age] < 100) {
            query_all.push_back(tmp);
            age_num[tmp.age] ++;
        }
    }
    // k次查询
    for (int i = 0; i < k; i ++) {
        int num, amin, amax, cnt = 0;
        scanf("%d %d %d",&num, &amin, &amax);
        // 选出满足年龄条件的人
        vector<People> query_list;
        for (int j = 0; j < query_all.size(); j ++) {
            if (query_all[j].age >= amin && query_all[j].age <= amax) {
                query_list.push_back(query_all[j]);
                cnt ++;
            }
        }
        // 输出
        cout << "Case #" << i+1 << ":" << endl;
        if (cnt == 0) {
            cout << "None" << endl;
        }
        else {
            for (int j = 0; j < num && j < query_list.size(); j ++) {
                printf("%s %d %d\n", query_list[j].name, query_list[j].age, query_list[j].money);
            }
        }
    }
    return 0;
}

总结

学习不息,继续加油

发现问题、解决问题的过程还是很有成就感的。

猜你喜欢

转载自blog.csdn.net/qq_34586921/article/details/83588457