【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

浙公网安备 33010602011771号