回 帖 发 新 帖 刷新版面

主题:第十一届全国青少年奥林匹克信息学联赛复赛提高组试题-谁拿了最多奖学金-文件输入常出现的问题,请看看!

[size=5][color=800000]  大家看看这道题,我做过了,原理很简单,可就是输入的时候有点问题,题要求先读名字,再读其它的,这就不免回用到字符串(也可不用,用s:array[1..n]of char),总之是输入的时候用字符串会将后面的一起读进去,请问大家该怎么解决?谢谢!!下面是原题:[/color][/size]
第十一届全国青少年奥林匹克信息学联赛复赛提高组试题 
 
发布日期:  2005-11-21  访问总次数:  20298  
  
(提高组  三小时完成)


谁拿了最多奖学金
(scholar.pas/c/cpp)

【问题描述】
某校的惯例是在每学期的期末考试之后发放奖学金。发放的奖学金共有五种,获取的条件各自不同:

1)院士奖学金,每人8000元,期末平均成绩高于80分(>80),并且在本学期内发表1篇或1篇以上论文的学生均可获得;

2)五四奖学金,每人4000元,期末平均成绩高于85分(>85),并且班级评议成绩高于80分(>80)的学生均可获得;

3)成绩优秀奖,每人2000元,期末平均成绩高于90分(>90)的学生均可获得;

4)西部奖学金,每人1000元,期末平均成绩高于85分(>85)的西部省份学生均可获得;

5)班级贡献奖,每人850元,班级评议成绩高于80分(>80)的学生干部均可获得;

只要符合条件就可以得奖,每项奖学金的获奖人数没有限制,每名学生也可以同时获得多项奖学金。例如姚林的期末平均成绩是87分,班级评议成绩82分,同时他还是一位学生干部,那么他可以同时获得五四奖学金和班级贡献奖,奖金总数是4850元。
现在给出若干学生的相关数据,请计算哪些同学获得的奖金总数最高(假设总有同学能满足获得奖学金的条件)。
【输入文件】
输入文件scholar.in的第一行是一个整数N(1 <= N <= 100),表示学生的总数。接下来的N行每行是一位学生的数据,从左向右依次是姓名,期末平均成绩,班级评议成绩,是否是学生干部,是否是西部省份学生,以及发表的论文数。姓名是由大小写英文字母组成的长度不超过20的字符串(不含空格);期末平均成绩和班级评议成绩都是0到100之间的整数(包括0和100);是否是学生干部和是否是西部省份学生分别用一个字符表示,Y表示是,N表示不是;发表的论文数是0到10的整数(包括0和10)。每两个相邻数据项之间用一个空格分隔。
【输出文件】
输出文件scholar.out包括三行,第一行是获得最多奖金的学生的姓名,第二行是这名学生获得的奖金总数。如果有两位或两位以上的学生获得的奖金最多,输出他们之中在输入文件中出现最早的学生的姓名。第三行是这N个学生获得的奖学金的总数。
【样例输入】
4
YaoLin 87 82 Y N 0
ChenRuiyi 88 78 N Y 1
LiXin 92 88 N N 0
ZhangQin 83 87 Y N 1
【样例输出】
ChenRuiyi
9000
28700

回复列表 (共13个回复)

沙发

由于程序数据范围只有100,当中不牵涉到数据移动,所以用一个纪录型数组,或者多个数组均可,在这里我们使用纪录型来描述。
    对于输入数据有两种方式来实现。
        法一〉逐个字符累加。
            首先定义C:char; 然后利用Until c=‘ ’;作为终止符,将读入的字符连接存储到a[i].name中。
            代码为:
                Repeat read(c); a[i].name:=a[i].name+c; until c=’ ‘; 
a[i].name:=copy(a[i].name,1,length(a[i].s)-1);
            这样做的好处是,后面的值可以直接用read语句读入。但是最后一个值后,要记得readln;

        法二〉一次读入,然后分离。
这样做需要逐个分离,对本题来说稍显复杂,但对NOIP来说此方法必须掌握,有的时候一定要用。
具体实现,读入一个字符串S。利用pos(‘ ‘,s);找出空格位置。再利用Copy函数,和Val函数进行截取,和转换。
部分代码:(s:string;j,ok:integer)
    readln(s);
    j:=pos(‘ ‘,s);
    a[i].name:=copy(s,1,j-1);
    s:= copy(s,j+1,50); //当长度〉字符串长度是,为后面全部截取。
    j:=pos(‘ ‘,s);
    Val(copy(s,1,j-1),a[i].qp,ok);
    s:= copy(s,j+1,50);
…..
对于符号用if语句作一下判断就是了,太easy不写了,后面还有几个值,用同样方法处理就可以了。

板凳

第一种:
  Repeat read(c); a[i].name:=a[i].name+c; until c=’ ‘; 
   a[i].name:=copy(a[i].name,1,length(a[i].[color=800000][size=4]s[/size][/color])-1);请问这里的S是怎么回事?也就是说a[i].name:=copy(a[i].name,1,length(a[i].[color=800000][size=4]s[/size][/color])-1);[/color]有什么用的?
 第二种: 
  还有就是这段程序我没懂:
    ......
    s:= copy(s,j+1,50); //当长度〉字符串长度是,为后面全部截取。
    j:=pos(‘ ‘,s);
    Val(copy(s,1,j-1),a[i].qp,ok);
    s:= copy(s,j+1,50);
    ......
请再详细地讲一下,谢谢!!

3 楼

copy(st,m,n)就是从字符串st的第m位开始取n位
比如copy('ABCabc', 2, 4)就是'BCab'

4 楼

[quote]第一种:
  Repeat read(c); a[i].name:=a[i].name+c; until c=’ ‘; 
   a[i].name:=copy(a[i].name,1,length(a[i].[color=800000][size=4]s[/size][/color])-1);请问这里的S是怎么回事?也就是说a[i].name:=copy(a[i].name,1,length(a[i].[color=800000][size=4]s[/size][/color])-1);[/color]有什么用的?

[/quote]

这个我估计是他用了个记录类型,a[i].name 是名字, a[i].s是整个一行字符串
不过看起来貌似还有些问题......

5 楼

最头疼的就是这个名字是几个字符的问题,由于没有办法知道每个人的名字是几个字符,所以只能从右往左取。

这里要分5步:

第1步:取最后的2个字符(因为论文总数最多2位数),如果第一个是空格,就舍弃。
第2步:用DELETE剔除这个字符串的后2位,剩余字符串取最后一位,就是这个学生是不是西部的人的标志。
第3步:再剔除余串的最后2位,余串取最后1位,就是这个学生是不是干部的标志。
第4步:再剔除余串的最后2位,这里可有点难受:
必须从余串最后一个字符开始取到发现的空格为止。就是这个人的班级评议成绩。
第5步:这里和第4步一样,取出来的数为期末考试成绩,我就不说了。
接着再去掉这个成绩的字符就是名字了。

我们可以设立以下6个变量:
name: STRING                     {这个人的名字}
test_score: INTEGER              {这个人的期末考试成绩}
class_score: INTEGER             {这个人的班级评议成绩}
is_monitor: BOOLEAN              {这个人是不是干部}
is_western: BOOLEAN              {这个人是不是西部的}
composition: INTEGER             {这个人发表的论文总数}

接着可以知道这个人获得了哪些奖学金。
money := 0;
IF (test_score > 80) AND (composition >= 1) THEN money := money + 8000;                                                {院士奖学金}
IF (test_score > 85) AND (class_score > 80) THEN money := money + 4000;                                                {五四奖学金}
IF (test_score > 90) THEN money := money + 2000;     {成绩优秀奖}
IF (test_score > 85) AND (is_western) THEN money := money + 1000;                                                {西部奖学金}
IF (class_score > 80) AND (is_monitor) THEN money := money + 850;
                                                     {班级贡献奖}

6 楼

谢谢!5楼的方法很有创意!
  有谁能解决2楼的问题?

7 楼

改一下:S改为NAME.
不小心打错了~~~

8 楼

请7楼的abcwuhang再帮我讲一下你的第二种方案,谢谢!

9 楼

讲评:
部分代码:(s:string;j,ok:integer)
    readln(s);{读入字符串}
    j:=pos(‘ ‘,s);{找出第一个空格位置,它之前是名字,它之后是内容}
    a[i].name:=copy(s,1,j-1);{把名字赋值到a[i].name中}
    s:= copy(s,j+1,50); //当长度>字符串长度是,为后面全部截取。{把空格位置之前的东东(名字)删除,为找成绩做准备}
    j:=pos(‘ ‘,s);{再找空格位置,即是第一个成绩和第二个成绩之间的位置}
    Val(copy(s,1,j-1),a[i].qp,ok);{把成绩赋值到ok中}
    s:= copy(s,j+1,50);{把空格位置之前的成绩删除,为后一轮的找成绩作准备}
…..类似重复上面的,直到把数据全部输入完毕

10 楼

为什么"s:= copy(s,j+1,50);"这里是50?
val的用法是怎么样的?也就是说请举个例子,比如将'86'这个字符串转换到a[i].qm中去.

我来回复

您尚未登录,请登录后再回复。点此登录或注册