题目描述
华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在 1111 分制和 2121 分制下,双方的比赛结果(截至记录末尾)。
比如现在有这么一份记录,(其中 WW 表示华华获得一分,LL 表示华华对手获得一分):
WWWWWWWWWWWWWWWWWWWWWWLWWWWWWWWWWWWWWWWWWWWWWWLW
在 1111 分制下,此时比赛的结果是华华第一局 1111 比 00 获胜,第二局 1111 比 00 获胜,正在进行第三局,当前比分 11 比 11。而在 2121 分制下,此时比赛结果是华华第一局 2121 比 00 获胜,正在进行第二局,比分 22 比 11。如果一局比赛刚开始,则此时比分为 00 比 00。直到分差大于或者等于 22,才一局结束。
你的程序就是要对于一系列比赛信息的输入(WLWL 形式),输出正确的结果。
输入格式
每个输入文件包含若干行字符串,字符串有大写的 WW 、 LL 和 EE 组成。其中 EE 表示比赛信息结束,程序应该忽略 EE 之后的所有内容。
输出格式
输出由两部分组成,每部分有若干行,每一行对应一局比赛的比分(按比赛信息输入顺序)。其中第一部分是 1111 分制下的结果,第二部分是 2121 分制下的结果,两部分之间由一个空行分隔。
输入输出样例
输入 #1复制
WWWWWWWWWWWWWWWWWWWW WWLWE
输出 #1复制
11:0 11:0 1:1 21:0 2:1
说明/提示
每行至多 2525 个字母,最多有 25002500 行。
(注:事实上有一个测试点有 25012501 行数据。)
【题目来源】
NOIP 2003 普及组第一题
参考代码如下:
#include <iostream>
#include <cmath>
using namespace std;
int f[2] = {11, 21};
int a[25 * 2500 + 10], n = 0;
int main() {
char tmp;
while (1) {
cin >> tmp; //用单个字符变量读入胜负情况
if (tmp == 'E') break; //读到‘E’时直接结束读入
else if (tmp == 'W') a[n++] = 1; //华华赢
else if (tmp == 'L') a[n++] = 0; //华华输
}
for (int k = 0; k < 2; k++) { //用for循环代替两种赛制
int w = 0, l = 0; //w代表赢,l代表输
for (int i = 0; i < n; i++) { //遍历用于记录输赢情况的数组
w += a[i]; l += 1 - a[i];
if ((max(w, l) >= f[k]) && abs(w - l) >= 2) { //比赛大比分超出对手两分
cout << w << ":" << l << endl;
w = l = 0;
}
}
cout << w << ":" << l << endl;
cout << endl;
}
return 0;
}
尽管本题是难度较低的模拟算法入门题,但其对我的启发还是不小。
首先是题目中所要求的输入格式:每行至多 25 个字母。
在模拟类型的题目中,题目的输出格式往往比较令我头疼,在选择使用cin函数和scanf函数的时候有些不知道如何下手,尤其是对于字符串的读入比较令我头疼。自己遇到的问题包括但不限于以下几种。
1.读入字符串时忽略了空格也需要被读入,但使用了scanf函数。
scanf函数工作的原理是不断地读入键盘上输入的字符串,直到遇见空格或回车就停下,并把空格和回车存储在缓冲区中等待下次读入。因此,空格并不会被scanf函数接受并赋值给string变量或者存放字符数组中。而解决读入空格问题需要用到fgets函数。
2.当题目中需要读入多行字符串时,往往会遇到行末的回车被读入到下一行字符串中,从而导致程序运行结果出错。
如第1个问题中所描述的,scanf遇到 回车(enter),空格,TAB 就会结束一次输入,并且, scanf在一次输入结束后,不会舍弃最后的回车符(即回车符会残留在数据缓冲区中)。
先看以下代码:
#include <stdio.h>
int main(){
char c1,c2;
scanf("%c %c",&c1,&c2); //这里有一个空格
printf("%d %d\n",c1,c2);
scanf("%c%c",&c1,&c2); //这里没有空格
printf("%d %d\n",c1,c2);
return 0;
}
输入输出如下:
发现第二次输出scanf函数将回车\n读入到了c1变量。
那么该如何解决这种问题呢?我们可以这样改一下:
#include <stdio.h>
int main(){
char c1,c2;
scanf("%c %c",&c1,&c2); //这里有一个空格
printf("%d %d\n",c1,c2);
scanf(" %c %c",&c1,&c2); //这里也有了空格
printf("%d %d\n",c1,c2);
return 0;
}
在第二段代码中,第二个scanf函数读入的最前端加了一个空格(换成\n或者\t也可以),这样就把缓冲区中的回车当成第一个字符,读取后丢掉 。并且这样可以避免使用getchar()函数吸收掉回车而造成的问题。
可以很好理解scanf中 空格的作用:
空格( )即为读取一个结束字符然后丢掉,而普通的字符不受影响。
用好之后可以避免很多程序BUG。
因此,此题参考代码中的读入方法可以满足题目中要求每行最多25个字符,同时可以忽略掉回车对于读入这么长的字符串的影响。
该方法是不用字符数组或者string变量来存储读入的字符串,而是用单个的字符变量,通过while循环来边读边判断双方的胜负情况,这样可以完全忽略掉scanf读入回车的问题(当然这种问题的解决方法同上方法2.)
解决掉该题的读入问题后,后面的过程就按照题目要求逐步模拟即可轻松解决。
同时也要有意识地去使用cmath库中的max、abs等函数来作为判断条件。
本文仅作为自己学习轨迹的记录
参考:【C语言】scanf语句吃掉回车或者空格问题详解 作者:Z小旋
以上。