题意:
模拟OJ的成绩排名。 输入:题数n、单位罚时m;之后每行数据代表一个学生的信息:用户名(不超过10个字符)、n道题的的得分现状。 每道题的得分现状:负数表示该学生在该题上有过的错误提交次数但到现在还没有AC,正数表示AC所耗的时间,如果正数a跟上了一对括号,里面有个正数b,则表示该学生AC了这道题,耗去了时间a,同时曾经错误提交了b次 每个同学的时间分=(AC所耗的时间+错误提交×单位罚时) 对于没有AC的题目,不需要管它,错误提交也不计入时间分 输出排名:先按AC题数的多少排,多的在前,再按时间分的多少排,少的在前,如果凑巧前两者都相等,则按名字的字典序排,小的在前。
做法:
结构体Student记录每个学生的用户名(name)、AC题数(cnt)、时间分(grade),重写比较方法,第一关键字cnt降序、第二关键字grade升序、第三关键字name升序。 vector<Student>保存所有学生。 字符串s循环读入得分现状,使用stoi将其转换成数字,若该数字<=0,不做处理;若该数字大于0,AC题数cnt++,然后遍历字符串s的每个字符直到找到"(",从下一个字符开始模拟读入,直到")",得到错误提交次数。该同学的时间分+=错误提交次数×单位罚时。构造该同学的Student添加进vector。 使用sort函数对vector进行排序,cout<<setw(n)<<left/right<<......<<endl;控制输出格式。
代码:
#include<cstdio>
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<iomanip>
using namespace std;
//学生结构体
struct Student{string name;//用户名 int cnt;//AC题数 int grade;//时间分 //重写比较方法 bool operator<(const Student&p)const{if(cnt!=p.cnt) return cnt>p.cnt;//第一关键字 AC题数 降序 if(grade!=p.grade) return grade<p.grade;//第二关键字 时间分 升序 if(name!=p.name) return name<p.name;//第三关键字 用户名 升序 }
};
int main()
{int n,m;string name;string s;//每道题的得分现状 vector<Student> v;cin>>n>>m;while(cin>>name){Student p;p.name=name;int grade=0;//时间分 int cnt=0;//AC题数 for(int i=0;i<n;i++){cin>>s;//读入一个题的得分现状int temp=stoi(s);//转换为数字 if(temp<=0){}//小于0 不需处理 else{cnt++;//AC题数++ grade+=temp;//AC所耗的时间 int k=0;while(s[k]!='('&&k<s.size()) k++; //略过(前面的字符 int y=0;//错误提交次数 k++;while(s[k]!=')'&&k<s.size()){//模拟读入 y=y*10+s[k]-'0';k++;}grade+=m*y;//罚时 } }p.cnt=cnt;p.grade=grade; v.push_back(p);//将该学生加入vector }//排序 sort(v.begin(),v.end());for(int j=0;j<v.size();j++){cout<<setw(10)<<left<<v[j].name<<" ";cout<<setw(2)<<right<<v[j].cnt<<" ";cout<<setw(4)<<right<<v[j].grade<<endl;}return 0;
}
改进:
巧妙处理得分现状的读入:通过sscanf("s,%d(%d)",&a,&b)返回的读入的个数,区分不同的得分现状
改进部分的代码:
cin>>s;//读入一个题的得分现状
if(sscanf(s,"%d(%d)",&a,&b)==1){//s是一个char数组if(a>0){cnt++;grade+=a;}
}else{cnt++;grade=grade+a+b*m;
}
总结:
scanf格式读入可以方便的处理字符串