一、概述
给出若干考生的考生号,每位意义不同。找出满足条件的考生。
字符串处理问题。
我的解题思路还是有很大缺陷的。
一开始我就确定了思路:利用sscanf分解考生号,使用结构体储存每一位考生的信息。
然后遇到了第一个问题,sscanf不会用。
调函数调了半天,调好了。
然后开始处理三种询问。
注意这里,要有一个中心思想,就是仅处理“合法的”,用字符串的角度处理。否则会犯和我一样的错误,只能得十五分。哭出来。
“合法的”指的是什么呢?指的是在题目中要求的范围,具体来说就是:
询问类型只考虑123,对于1,只考虑bat,对于二,只考虑数字,对于3,也只考虑数字。
用字符串的角度处理指的又是什么呢?指的是不要把输入看成数字,全看成字符串,不然debug有的受,具体来说就是:
比如说2,我们需要输入考场号,一看有效范围100-999,就用%d输入int吧。错了,不行。为什么不行?因为输入可能是字符,就是abc什么的。这就是边界条件。
而scanf用%d时有一个特点,遍历缓冲区,可以认为是打回车前的输入,找到第一个数字,逮出来赋值。
那么如果我缓冲区没有数字怎么办?scanf遍历一遍,没找着,过去了。但是它也不敢清空缓冲区啊,没那个胆子也没那个权限。
那么我们看查询如果输入 2 B会出现什么情况:
首先%d输入2,发现是二号询问,问考场考生的,然后%d输入考场号,由于2被拿走了,剩个B,这个scanf找不着数字,就跳过,报NA,不清缓冲区。下一次又是输入2,又发现是二号询问,无限循环。。。
发现了什么?就是需要根据输入响应输出时候,如果题中没给限制(比如说图论中,所有节点编号为1-N,或者所有输入均为非负不同整数),那么就不能耿直的按正确的输入,要按字符串输入。谁知道神经病使用者会输入什么玩意儿进来。
二、分析
(一)字符串数组风格
对于这种分割字符串题目,如果要用sscanf,注意三点:
1、sscanf的第一个参数是一个大字符串
2、sscanf的第三个参数,如果不是字符串,要加&
3、sscanf的第二个参数,可以加数量限制,比如说我要一个字符,就可以%1s
因此输入处理如下:
struct student
{
char level[10];
char set[10];
char date[10];
char num[10];
int score;
char ID[20];
string realID;
}S[10010];
int N,M;
scanf("%d %d",&N,&M);
for(int i=0;i<N;i++)
{
scanf("%s %d",S[i].ID,&S[i].score);
sscanf(S[i].ID,"%1s%3s%6s%3s",S[i].level,S[i].set,S[i].date,S[i].num);
S[i].realID=S[i].ID;
}
为什么我要有一个realID呢,因为用string可以直接在cmp里比较,这样方便。
sort没法对两个字符串数组比较大小,必须转为string,char数组转string还是很简单的,直接等于号赋值即可。
score要用int保存,不能用字符串数组,因为用字符串数组的话,99就跑到100前面去了,因为9比1大。
所以还是很麻烦的。
然后处理询问。如下:
for(int i=1;i<=M;i++)
{
char q;
cin>>q;
if(q=='1')
{
char x[10];
cin>>x;
cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
vector<student> v;
if(!strcmp(x,"B")||!strcmp(x,"A")||!strcmp(x,"T"))
{
for(int j=0;j<N;j++)
{
if(!strcmp(S[j].level,x))
v.push_back(S[j]);
}
if(v.size()==0)
printf("NA\n");
else
{
sort(v.begin(),v.end(),cmp);
for(int k=0;k<v.size();k++)
printf("%s %d\n",v[k].ID,v[k].score);
}
}
else
printf("NA\n");
}
else if(q=='2')
{
char x[10];
cin>>x;
cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
int num=0;
int sum=0;
for(int j=0;j<N;j++)
{
if(!strcmp(S[j].set,x))
{
num++;
sum+=S[j].score;
}
}
if(num>0)
printf("%d %d\n",num,sum);
else
printf("NA\n");
}
else if(q=='3')
{
char x[10];
cin>>x;
cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
unordered_map<int,int> m;
for(int j=0;j<N;j++)
{
if(!strcmp(S[j].date,x))
{
m[atoi(S[j].set)]++;
}
}
if(m.size()==0)
printf("NA\n");
else
{
vector<node> v;
unordered_map<int,int>::iterator it;
for(it=m.begin();it!=m.end();it++)
{
node leaf;
leaf.set=it->first;
leaf.num=it->second;
v.push_back(leaf);
}
sort(v.begin(),v.end(),cmp1);
vector<node>::iterator iter;
for(iter=v.begin();iter!=v.end();iter++)
{
printf("%d %d\n",iter->set,iter->num);
}
}
}
else
{
string x;
cin>>x;
//scanf("%s",x);
cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
cout<<"NA\n";
//printf("Case %d: %s %s\nNA\n",i,q,x);
}
}
首先注意一点,询问的两个参数,都用字符串数组存储。
然后判断。容易出错的有以下几个地方:
询问1,要先选出对应级别的人,再排序。而不能最开始全排序好。那样顺序有问题。如果输入不是BAT,要输出NA,如果输入的是BAT但是人数为0,也要输出NA。如果最开始选择vector存储,然后排序,判断人数,就简单一些。
询问2,应该是最简单的了。选择对应考场的然后累加即可。
询问3,最麻烦。因为要注意两个参数,考场和人数,先按人数再按考场排。要选出对应日期的人,存在哪里呢?可以存在map里。map如果第二个参数是int,那么不赋值时就是0,很方便。但是我们注意map是有序的,这就意味着对其进行插入操作会花时间,而且map这个有序的特性我们也用不着。于是可以使用undered_map。这个单纯是个hash表,没有排序特性,我们利用哈希特性就好了。在unordered_map中存完之后,用一个结构体vector再转存一遍。然后对vector再排序输出即可。
注意如果出现询问567abc,那也要返回NA。
这样就可以了。
(二)string风格
我们可以看出,使用字符串数组还是有点麻烦的,主要麻烦在排序、判断相等、还占空间。如果能直接在考生号里面进行比较就好了。这时,我们要拿出subctr函数。
substr是string的一个函数,参数有两个,a,b,用于返回从a开始长度为b的子串。用这个就可以实现我们要的功能了。
首先结构体和输入就简单得多。
struct student
{
string ID;
int score;
}s[100100];
for(int i=0;i<N;i++)
{
cin>>s[i].ID;
cin>>s[i].score;
}
看上去十分赏心悦目啊。
然后是处理询问。注意能不用switch就不用switch。使用strsub之后比较相等简直简单了很多。具体的逻辑实现还是没什么区别的。如下:
for(int i=1;i<=M;i++)
{
string q,x;
cin>>q;
cin>>x;
cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
if(q=="1")
{
vector<student> v;
for(int j=0;j<N;j++)
{
if(s[j].ID.substr(0,1)==x)
{
v.push_back(s[j]);
}
}
sort(v.begin(),v.end(),cmp);
if(v.size()!=0)
{
for(int k=0;k<v.size();k++)
{
cout<<v[k].ID<<" "<<v[k].score<<"\n";
}
}
else
cout<<"NA\n";
}
else if(q=="2")
{
int num=0,sum=0;
for(int j=0;j<N;j++)
{
if(s[j].ID.substr(1,3)==x)
{
num++;
sum+=s[j].score;
}
}
if(num!=0)
printf("%d %d\n",num,sum);
else
cout<<"NA\n";
}
else if(q=="3")
{
unordered_map<string,int> m;
for(int j=0;j<N;j++)
{
if(s[j].ID.substr(4,6)==x)
{
m[s[j].ID.substr(1,3)]++;
}
}
if(m.size()==0)
cout<<"NA\n";
else
{
unordered_map<string,int>::iterator it;
vector<node> v;
for(it=m.begin();it!=m.end();it++)
{
node leaf;
leaf.num=it->second;
leaf.set=it->first;
v.push_back(leaf);
}
sort(v.begin(),v.end(),cmp1);
for(int j=0;j<v.size();j++)
{
cout<<v[j].set<<" "<<v[j].num<<"\n";
}
}
}
else
{
cout<<"NA\n";
}
}
三、总结
字符串处理,substr是利器,用于只要求比较相等而不需要具体找出来再处理。如果需要找出来然后处理的话也可以用sscanf和sprintf。
string还有一个函数也很好用,就是fing,成功时返回首位位置,失败时返回string::npos,就是失败这个比较难记。
PS:代码如下:
字符串版:
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<unordered_map>
using namespace std;
struct student
{
char level[10];
char set[10];
char date[10];
char num[10];
int score;
char ID[20];
string realID;
}S[10010];
struct node
{
int set;
int num=0;
};
bool cmp(student a,student b)
{
if(a.score!=b.score)
return a.score>b.score;
else
return a.realID<b.realID;
/*if(a.level!=b.level)
return a.level<b.level;
else
return a.score>b.score;*/
}
bool cmp1(node a,node b)
{
if(a.num!=b.num)
return a.num>b.num;
else
return a.set<b.set;
}
int main()
{
int N,M;
scanf("%d %d",&N,&M);
for(int i=0;i<N;i++)
{
scanf("%s %d",S[i].ID,&S[i].score);
sscanf(S[i].ID,"%1s%3s%6s%3s",S[i].level,S[i].set,S[i].date,S[i].num);
S[i].realID=S[i].ID;
}
//sort(S,S+N,cmp);不应该在这里排序
for(int i=1;i<=M;i++)
{
char q;
cin>>q;
if(q=='1')
{
char x[10];
cin>>x;
cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
vector<student> v;
if(!strcmp(x,"B")||!strcmp(x,"A")||!strcmp(x,"T"))
{
for(int j=0;j<N;j++)
{
if(!strcmp(S[j].level,x))
v.push_back(S[j]);
}
if(v.size()==0)
printf("NA\n");
else
{
sort(v.begin(),v.end(),cmp);
for(int k=0;k<v.size();k++)
printf("%s %d\n",v[k].ID,v[k].score);
}
}
else
printf("NA\n");
}
else if(q=='2')
{
char x[10];
cin>>x;
cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
int num=0;
int sum=0;
for(int j=0;j<N;j++)
{
if(!strcmp(S[j].set,x))
{
num++;
sum+=S[j].score;
}
}
if(num>0)
printf("%d %d\n",num,sum);
else
printf("NA\n");
}
else if(q=='3')
{
char x[10];
cin>>x;
cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
unordered_map<int,int> m;
for(int j=0;j<N;j++)
{
if(!strcmp(S[j].date,x))
{
m[atoi(S[j].set)]++;
}
}
if(m.size()==0)
printf("NA\n");
else
{
vector<node> v;
unordered_map<int,int>::iterator it;
for(it=m.begin();it!=m.end();it++)
{
node leaf;
leaf.set=it->first;
leaf.num=it->second;
v.push_back(leaf);
}
sort(v.begin(),v.end(),cmp1);
vector<node>::iterator iter;
for(iter=v.begin();iter!=v.end();iter++)
{
printf("%d %d\n",iter->set,iter->num);
}
}
}
else
{
string x;
cin>>x;
//scanf("%s",x);
cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
cout<<"NA\n";
//printf("Case %d: %s %s\nNA\n",i,q,x);
}
}
}
string版:
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<unordered_map>
using namespace std;
struct student
{
string ID;
int score;
}s[100100];
struct node
{
string set;
int num;
};
bool cmp(student a,student b)
{
if(a.score!=b.score)
return a.score>b.score;
else
return a.ID<b.ID;
}
bool cmp1(node a,node b)
{
if(a.num!=b.num)
return a.num>b.num;
else
return a.set<b.set;
}
int main()
{
int N,M;
scanf("%d %d",&N,&M);
for(int i=0;i<N;i++)
{
cin>>s[i].ID;
cin>>s[i].score;
}
for(int i=1;i<=M;i++)
{
string q,x;
cin>>q;
cin>>x;
cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
if(q=="1")
{
vector<student> v;
for(int j=0;j<N;j++)
{
if(s[j].ID.substr(0,1)==x)
{
v.push_back(s[j]);
}
}
sort(v.begin(),v.end(),cmp);
if(v.size()!=0)
{
for(int k=0;k<v.size();k++)
{
cout<<v[k].ID<<" "<<v[k].score<<"\n";
}
}
else
cout<<"NA\n";
}
else if(q=="2")
{
int num=0,sum=0;
for(int j=0;j<N;j++)
{
if(s[j].ID.substr(1,3)==x)
{
num++;
sum+=s[j].score;
}
}
if(num!=0)
printf("%d %d\n",num,sum);
else
cout<<"NA\n";
}
else if(q=="3")
{
unordered_map<string,int> m;
for(int j=0;j<N;j++)
{
if(s[j].ID.substr(4,6)==x)
{
m[s[j].ID.substr(1,3)]++;
}
}
if(m.size()==0)
cout<<"NA\n";
else
{
unordered_map<string,int>::iterator it;
vector<node> v;
for(it=m.begin();it!=m.end();it++)
{
node leaf;
leaf.num=it->second;
leaf.set=it->first;
v.push_back(leaf);
}
sort(v.begin(),v.end(),cmp1);
for(int j=0;j<v.size();j++)
{
cout<<v[j].set<<" "<<v[j].num<<"\n";
}
}
}
else
{
cout<<"NA\n";
}
}
}