题目:
程序设计思维作业和实验使用的实时评测系统,具有及时获得成绩排名的特点,那它的功能是怎么实现的呢?
我们千辛万苦怼完了不忍直视的程序并提交以后,评测系统要么返回AC,要么是返回各种其他的错误,不论是怎样的错法,它总会给你记上一笔,表明你曾经在这儿被坑过,而当你历经千辛终将它AC之后,它便会和你算笔总账,表明这题共错误提交了几次。
在岁月的长河中,你通过的题数虽然越来越多,但通过每题时你所共花去的时间(从最开始算起,直至通过题目时的这段时间)都会被记录下来,作为你曾经奋斗的痕迹。特别的,对于你通过的题目,你曾经的关于这题的每次错误提交都会被算上一定的单位时间罚时,这样一来,你在做出的题数上,可能领先别人很多,但是在做出同样题数的人中,你可能会因为罚时过高而处于排名上的劣势。
例如某次考试一共八道题(A,B,C,D,E,F,G,H),每个人做的题都在对应的题号下有个数量标记,负数表示该学生在该题上有过的错误提交次数但到现在还没有AC,正数表示AC所耗的时间,如果正数a跟上了一对括号,里面有个正数b,则表示该学生AC了这道题,耗去了时间a,同时曾经错误提交了b次。例子可见下方的样例输入与输出部分。
Input:
输入数据包含多行,第一行是共有的题数n(1≤n≤12)以及单位罚时m(10≤m≤20),之后的每行数据描述一个学生的信息,首先是学生的用户名(不多于10个字符的字串)其次是所有n道题的得分现状,其描述采用问题描述中的数量标记的格式。
Output:
根据这些学生的得分现状,输出一个实时排名。实时排名显然先按AC题数的多少排,多的在前,再按时间分的多少排,少的在前,如果凑巧前两者都相等,则按名字的字典序排,小的在前。每个学生占一行,输出名字(10个字符宽),做出的题数(2个字符宽,右对齐)和时间分(4个字符宽,右对齐)。名字、题数和时间分相互之间有一个空格。数据保证可按要求的输出格式进行输出。
Sample Input:
8 20
GuGuDong 96 -3 40(3) 0 0 1 -8 0
hrz 107 67 -3 0 0 82 0 0
TT 120(3) 30 10(1) -3 0 47 21(2) -2
OMRailgun 0 -99 -8 0 -666 -10086 0 -9999996
yjq -2 37(2) 13 -1 0 113(2) 79(1) -1
Zjm 0 0 57(5) 0 0 99(3) -7 0
Sample Output:
TT 5 348
yjq 4 342
GuGuDong 3 197
hrz 3 256
Zjm 2 316
OMRailgun 0 0
题目分析:
该题最关键的是理解测评系统的测算方式并进行正确的提取字符串内容。对于该题的情况而言,有几点:
- 一是含有空格的字符串读取;可以采用getline直接一整行的读取,然后再利用strtok()函数进行字符分割;也可以像这里一样,先利用标准输入cin或者scanf读入一个字符串(默认空格为结束),然后再利用循环继续输入其他剩下的字符串,这就不用再进行分割了,因为已经自动利用空格为结束符分割完毕。
- 二是字符串包含括号的情况,需要识别括号并分别提取括号内外的内容;定义一个函数,遍历字符串,当该字符串中包含括号时,做出标记,并将括号内和括号外分别保存在两个字符串数组中。
- 三是需要鉴别字符串是否为数字以及数字的正负,此处题解用到了字符串和string类型转换函数char pch=(char)my_string.data()以及char*类型转换为整数函数atoi()。
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<iomanip>
using namespace std;
const int maxn=1e3+5;
struct rrrank//注意结构体名字不能为rank(有的编译器会报错哦)
{
int ac;//ac题数 多的在前降序
int time;//时间分 少的在前升序
string name;//如果凑巧前两者都相等,则按名字的字典序排,小的在前升序
bool operator<(const rrrank &r)const//结构体重写比较
{
if(ac!=r.ac) return ac>r.ac;
if(time!=r.time) return time<r.time;
return name<r.name;
}
}st[maxn];
int extract(char *s,int m)//提取括号内外内容
{
int len=strlen(s);
int i=0;
for(;i<len;i++)
{
if(s[i]=='(')
{
break;
}
}
char temp1[128],temp2[128];
for(int j=0;j<i;j++)
{
temp1[j]=s[j];
}
int j,k;
for(j=i+1,k=0;j<len-1;j++,k++)
{
temp2[k]=s[j];
}
int temp=atoi(temp1);
int tempp=atoi(temp2)*m;
temp+=tempp;
return temp;
}
bool kuohao(char* s)//判断字符串是否包含括号
{
int len=strlen(s);
for(int i=0;i<len;i++)
{
if(s[i]=='(')
{
return true;
}
}
return false;
}
int main()
{
int n,m;//,m;//共有题数n以及单位罚时m
cin>>n>>m;
string my_string;
int k=0;
while(cin>>my_string)
{
st[k].name=my_string;
int count=0;
for(int i=0;i<n;i++)
{
cin>>my_string;
char *pch=(char*)my_string.data();//将string类型强制转换为char类型(因为atoi()函数参数类型只能为char类型
if(!kuohao(pch))
{
int temp=atoi(pch);
if(temp<=0)
{
count++;//count为不ac的数量
}
else
{
st[k].time+=temp;
}
}
else
{
st[k].time+=extract(pch,m);
}
st[k].ac=n-count;
}
k++;
}
sort(st,st+k);//多关键字排序
for(int i=0;i<k;i++)//按题目要求输出
{
cout<<setiosflags(ios::left)<<setw(10)<<st[i].name<<" ";
cout<<setiosflags(ios::right)<<setw(2)<<st[i].ac<<" ";
cout<<setiosflags(ios::right)<<setw(4)<<st[i].time<<endl;
cout<<resetiosflags(ios::right);
}
system("pause");
return 0;
}
因为while(cin>>my_string)没有结束条件,在调试的时候,Windows下可以通过ctrl+z来执行EOF,(顺便查了一下其他系统的EOF值,visual studio 2017下为ctrl+c,linux/unix下为ctrl+c或ctrl+d)这样你就能看到你的输出啦!
关于输出格式,正如上面代码的输出部分所示,可以通过setiosflags()来控制对齐方式,通过setw()来控制字符宽度;但当时在写的时候遇到了一个问题,在第一参数设置左对齐,第二,三个设置右对齐的时候,因为默认右对齐,所以会出现第一个参数在循环中只有第一次循环时正确的左对齐,其他都是默认的右对齐,这就和理想中的不大一样了,所以一定要在循环体里加上cout<<resetiosflags(ios::right);加上就好啦!