题目链接: P1580 yyy loves Easter_Egg I
题解
模拟题。按照题意讨论不同情形,然后输出答案即可。因为比较思路显然,具体的模拟思路略去。这里着重讨论一下该题的坑点。
坑: 这题使用 getline
函数读取一行,字符串的末尾会出现一个回车符 '\r'
(具体原因后面会解释)。所以我们在提取第一个人所@的名字时,如果那个名字出现在句子末尾,后面极有可能紧跟着一个 '\r'
。因此要注意判断一下,防止把字符 '\r'
加入人名,造成错误。后面给出的代码中会有对应的注释。
为什么字符串的末尾会出现回车符呢?
众所周知,在不同的操作系统的文件中,在一行的末尾,换行符是不同的。例如:
- Unix/Linux 系统中,行末使用
'\n'
表示换行 - Windows 系统中,行末使用
'\r\n'
表示换行 - Mac 系统中,行末使用
'\r'
表示换行
因此一个系统上生成的文本文件,在另一个不同的系统上用文本编辑器打开,就可能出现一些问题,这是由不同的系统差异导致的。如果生成输入文件的系统是Windows,测评机的系统是Linux,那么在Linux的环境下, getline
默认以 '\n'
作为行的结束符,它不会自动剔除 '\r'
,而是把回车放到读取的字符串中,最终导致错误。这个错误本质上应该是出题者的锅,是生成文件的系统和测评机系统不一致导致的。
更进一步地,如果测评机也是Windows系统, getline
函数在Windows上的实现,使得它在Windows系统上可以自动去除多余 '\r'
,应该不会导致这样的错误。这一点我做了测试,并得到了验证。
实现的代码见下,变量的命名可能比较随意,不太直观。
#include <iostream>
#include <string>
using namespace std;
int main() {
int nline, fg = 0, pos = -1;
string ignr, info, name, speaker;
nline = 1;
getline(cin, info);
for (int i = 0, len = info.size(); i < len; ++i) {
if (info[i] == '@') {
i += 11;
name = "";
// !!! 注意判断回车符 '\r'
while (i < len && info[i] != ' ' && info[i] != '\r')
name += info[i], ++i;
break;
}
}
while (cin >> ignr && ignr.size() > 0) {
++nline;
if (fg) {
getline(cin, info);
continue;
}
cin >> ignr >> speaker;
getline(cin, info);
if (speaker == name) {
fg = 1;
} else {
int atnum = 0;
for (int i = 0, len = info.size(); i < len; ++i) {
if (info[i] == '@') {
if (++atnum != 1 || info.substr(i, 11 + name.size()) != "@yyy loves " + name) {
atnum = -1;
break;
}
}
}
if (atnum != 1) {
fg = 2;
pos = nline;
}
}
}
if (fg == 0) {
cout << "Unsuccessful @yyy loves " + name + " attempt" << endl;
cout << nline << endl;
cout << "Good Queue Shape" << endl;
} else if (fg == 1) {
cout << "Successful @yyy loves " + name + " attempt" << endl;
} else if (fg == 2) {
cout << "Unsuccessful @yyy loves " + name + " attempt" << endl;
cout << pos << '\n';
cout << "yyy loves " + speaker << '\n';
}
return 0;
}
总结
本来是觉得这题比昨天做的那题水,没必要写题解的,但是这题遇到的错误却值得花一些篇幅介绍一下。也算是深化了对换行符的认识吧。不得不说,这个错误确实是非常鬼畜(做模拟题果然可以看到一些不一样的东西)。这也算是一道至少需要两次提交才可AC的题目了吧。(如果你是个正常人的话(笑