【pta】7-45 航空公司VIP客户查询 (25 分) <map的使用和优化、sscanf的使用>

一、题目信息

题目链接:https://pintia.cn/problem-sets/15/problems/892

不少航空公司都会提供优惠的会员服务,当某顾客飞行里程累积达到一定数量后,可以使用里程积分直接兑换奖励机票或奖励升舱等服务。现给定某航空公司全体会员的飞行记录,要求实现根据身份证号码快速查询会员里程积分的功能。

输入格式:

输入首先给出两个正整数N(105)和K(500)。其中K是最低里程,即为照顾乘坐短程航班的会员,航空公司还会将航程低于K公里的航班也按K公里累积。随后N行,每行给出一条飞行记录。飞行记录的输入格式为:18位身份证号码(空格)飞行里程。其中身份证号码由17位数字加最后一位校验码组成,校验码的取值范围为0~9和x共11个符号;飞行里程单位为公里,是(0, 15 000]区间内的整数。然后给出一个正整数M(105),随后给出M行查询人的身份证号码。

输出格式:

对每个查询人,给出其当前的里程累积值。如果该人不是会员,则输出No Info。每个查询结果占一行。

输入样例:

4 500
330106199010080419 499
110108198403100012 15000
120104195510156021 800
330106199010080419 1
4
120104195510156021
110108198403100012
330106199010080419
33010619901008041x
 
结尾无空行

输出样例:

800
15000
1000
No Info
 
结尾无空行
 

二、第一版代码

 

#include <bits/stdc++.h>
using namespace std;

map<string,int>mp;

int main(void)
{
    ios::sync_with_stdio(0);
    int n,k;
    cin>>n>>k;
    string num;
    int km;
    while (n--){
        cin>>num>>km;
        if (km<k) km=k;
        mp[num]+=km;
    }
    int m;
    cin>>m;
    for (int i=0;i<m-1;i++)
    {
        cin>>num;
        if (mp[num]==0) cout<<"No Info"<<endl;
        else cout<<mp[num]<<endl;
    }
    cin>>num;
    if (mp[num]==0) cout<<"No Info";
    else cout<<mp[num];
    return 0;
}

 

 

由于超时,我又尝试了unordered_map,仍然超时。

三、ac代码

https://blog.csdn.net/qq_43189757/article/details/88901330?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-4.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-4.control

在阅读了这位大佬写的题解后,我尝试将map中string类型的映射改为long long类型的映射

#include <bits/stdc++.h>
using namespace std;
#define ll long long

unordered_map<ll,int>mp;

int main(void)
{
    int n,k,km,m;
    ll id;
    char num[20];
    scanf("%d %d",&n,&k);
    while(n--){
        scanf("%s %d",num,&km);
        if (km<k) km=k;
        if (num[17]!='x') sscanf(num,"%18lld",&id); //从字符串中读取,并转换为long long类型
        else sscanf(num,"%17lld",&id),id*=-1; //如果最后一位是'x',将这个id变成负的,这样就不会重复了
        mp[id]+=km;
    }
    scanf("%d",&m);
    for (int i=0;i<m-1;i++){
        scanf("%s",num);
        if (num[17]!='x') sscanf(num,"%18lld",&id);
        else sscanf(num,"%17lld",&id),id*=-1;
        if (mp.count(id)==0) printf("No Info\n");
        else printf("%d\n",mp[id]);
    }
    scanf("%s",num);
    if (num[17]!='x') sscanf(num,"%18lld",&id);
    else sscanf(num,"%17lld",&id),id*=-1;
    if (mp.count(id)==0) printf("No Info");
    else printf("%d",mp[id]);
    return 0;
}

 

在本题中,由于时间卡的比较紧(400ms),虽然题目是10^5,但是采用nlogn也容易超时,所以尽量采用scanf与printf减少时间,同时使用查找更快的unordered_map来查找。

而且对于字符串类型(一个一个字符查找)来说,查找(长)整型数字明显是效率更高的算法~

四、亿些知识点

unordered_map与map

最明显的几个不同:

unordered_map用哈希表来查找———map是通过红黑树来查找

unordered_map查找效率为O(1),最差为O(n)————map查找效率为O(logn)

unordered_map中的元素为无序的————map中的元素默认按key大小排序

所以——若对时间有要求使用unordered_map;对排序,查找稳定性有要求使用map

sscanf

sscanf与scanf最大的区别是:

scanf从键盘读取内容,sscanf从给定的字符串中读取内容

 

sscanf(num,"%18lld",&id);

 

如这行代码,第一个变量为要读取的字符串,第二、三个与平时scanf的用法相同

这位大佬将知识点整理了代码,此处简单展示 https://www.cnblogs.com/caijiaming/p/10349000.html

    //遇到指定字符为止的字符串  如在下例取遇到空格为止字符串
    sscanf("123456 abcde","%[^ ]",buf);
    printf("%s\n",buf);
    //输出结果为 123456    遇到空格结束
    sscanf("123456 abcd","%[^4]",buf);
    printf("%s\n",buf);
    //输出结果为123  遇到4结束

    //跳过此数据不读入
    sscanf("123456abcd","%*d%s",buf);
    printf("%s\n",buf);
    //输出结果为  abcd   跳过了整形

    //取到指定字符集为止的字符串
    sscanf("123456abcde","%[^a-z]",buf);
    printf("%s\n",buf);
    //输出结果为123456    遇到a小写字母停止读入

    sscanf("123456abcdDAD$^&&*","%[1-9a-z]",buf);
    printf("%s\n",buf);
    //输出结果为123456abcdc  只读指定字符

感谢所有大佬的代码!

peace

 

posted @ 2021-08-30 21:56  北辰ฅ  阅读(222)  评论(0)    收藏  举报