Online Judge - I/O
Created by : Mr Dk.
2021 / 03 / 11 15:29
Nanjing, Jiangsu, China
最近需要参加一些在线笔试。OJ 平台有以下两种模式:
- 核心代码模式 (以 LeetCode 为例):只需要编写核心函数,无需自行处理输入输出
- ACM 模式:需要自行编写代码读取输入,打印输出
对于 ACM 模式,特此记录各种处理输入的方式,防止笔试现场搞半天输入都处理不利索。
C++
对于输入中明确给出了具体输入的规模的简单情况,就不多加记录了。将具体的输入规模读取后,根据这个数字进行循环,即可获得所有输入。以下记录一些输入规模不确定,或没有显式停止标志的处理方法。
不确定输入的总组数,没有显式停止标志
这种输入没有显式的停止标志,文件尾或 Ctrl-Z
就是隐式的停止符号。对于这种输入,如果每组输入的规模确定,可以直接使用 while
+ cin
处理。比如,以下每行输入两个整数,输入组数不确定:
1 2
3 4
...
处理方法:
#include <iostream>
using namespace std;
int a, b;
while (cin >> a >> b) {
// ...
}
遇到输入结束时,while
循环也将结束。
不确定输入的总组数,有明确停止标志
对于有明确停止标志的输入,可以在 while
的循环条件中顺带对停止标志加以判断。比如,以下每行输入两个整数,以两个 0
结尾:
1 2
3 4
... ...
0 0
处理方法:
#include <iostream>
using namespace std;
int a, b;
while (cin >> a >> b && (a || b)) {
// ...
}
不确定输入总组数,不确定每行输入个数
由于不确定输入总组数,因此肯定只能通过 while
对每行输入进行读取。现在的问题是,每个输入的个数也不确定,只有显式指定的分隔符 (比如 或
,
),或是隐式指定的结尾 (行尾换行符)。比如,每行不确定输入个数,输入之间用空格分隔:
1 2 3
4 5
...
0 0 0 0 0
对于这种输入,处理方式为:首先用一个 while
每次读取输入的完整一行,作为外层循环;在内层循环中,对每一行的数据根据分隔符进行进一步分割。为了方便分割,可以使用 getline()
与 stringstream
配合:
#include <sstream>
string line;
while (getline(cin, line)) {
stringstream ss(line);
string each_word;
while (getline(ss, each_word, ' ')) {
// deal with each_word ...
}
}
getline()
能够接受一个流作为参数,所以可以接受标准输入流 / 字符串流 / 文件流等。另外,getline()
会在遇到停止符号时截取字符串,并丢弃停止符号本身,然后添加上 \0
后作为输出结果。默认的停止符号为换行符,但可以通过函数参数自行指定,另外,遇到字符串结尾、流结尾时自然也会结束。
上述代码中,外层循环中的 getline()
从标准输入流中获取一行输入,在遇到换行符时,抛弃掉换行符后,将已接收的一行字节数据保存在 string
对象中,即一行完整的数据。内层循环中的 getline()
从封装为 stringstream
流的字符串中获取输入,直到遇到指定的空格停止符,抛弃掉空格后,将输出保存到 string
对象中;当到达字符串流的中止符时,也自然停止并返回行内最后一个输入。
以上方式同样适用于每行输入中使用非空格分隔符。
重定向输入
每次重新运行程序进行测试时,都要手动输入数据,麻烦。将输入提前写在文件中,并将 标准输入 重定向到文件,就省得每次动手输入了。在程序中,仅需一行代码就可以实现输入重定向:
freopen("input.txt", "r", stdin);
该函数原本定义在 stdio.h
中。在运行时,可根据环境使用 <stdio.h>
(C) 或 <cstdio>
(C++)。
在提交前记得注释这一行!