1. ACM模式输入输出概述
在算法竞赛和编程面试中,ACM模式是最常见的输入输出处理方式。与LeetCode等平台的核心代码模式不同,ACM模式要求选手自行处理完整的输入输出流程。这种模式更贴近实际工程开发场景,能够全面考察选手的编程基本功。
ACM模式的特点:
- 需要处理标准输入(stdin)和标准输出(stdout)
- 输入数据通常以特定格式给出,需要正确解析
- 输出格式有严格要求,必须完全匹配题目要求
- 需要考虑大数据量下的性能问题
2. 基础输入输出方法
2.1 单行固定数量输入
这是最简单的输入情况,每行包含固定数量的数据项。
示例输入:
code复制1 2
3 4
C++处理代码:
cpp复制#include <iostream>
using namespace std;
int main() {
int a, b;
while (cin >> a >> b) {
cout << a + b << endl;
}
return 0;
}
关键点:
cin会自动跳过空白字符(空格、制表符、换行符)while(cin >> a >> b)会持续读取直到输入结束- 输出后要记得换行
2.2 先读数量再读数据
常见于需要先知道数据规模的情况。
示例输入:
code复制3
1 2 3
4
5 6 7 8
C++处理代码:
cpp复制#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
while (cin >> n) {
vector<int> nums(n);
for (int i = 0; i < n; ++i) {
cin >> nums[i];
}
// 处理数据...
}
return 0;
}
3. 高级输入处理技巧
3.1 不定长单行输入
当一行数据项数量不固定时,需要特殊处理。
示例输入:
code复制1 2 3 4 5
6 7
8 9 10
C++处理代码:
cpp复制#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main() {
string line;
while (getline(cin, line)) {
istringstream iss(line);
vector<int> nums;
int num;
while (iss >> num) {
nums.push_back(num);
}
// 处理数据...
}
return 0;
}
关键点:
getline读取整行,包括空格istringstream将字符串转为流方便分割- 适用于数据项数量未知的情况
3.2 带分隔符的输入
当数据项用特定分隔符(如逗号)分隔时。
示例输入:
code复制1,2,3,4,5
6,7
8,9,10
C++处理代码:
cpp复制#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main() {
string line;
while (getline(cin, line)) {
istringstream iss(line);
vector<int> nums;
string item;
while (getline(iss, item, ',')) {
nums.push_back(stoi(item));
}
// 处理数据...
}
return 0;
}
4. 字符串处理技巧
4.1 单行字符串输入
处理单行字符串输入的基本方法。
示例输入:
code复制hello world
algorithm
C++处理代码:
cpp复制#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
while (getline(cin, s)) {
// 处理字符串...
}
return 0;
}
4.2 多行字符串输入
处理多行字符串输入,每行可能有多个字符串。
示例输入:
code复制3
apple banana orange
cat dog
red green blue
C++处理代码:
cpp复制#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
int n;
cin >> n;
cin.ignore(); // 忽略换行符
vector<vector<string>> lines(n);
for (int i = 0; i < n; ++i) {
string line;
getline(cin, line);
istringstream iss(line);
string word;
while (iss >> word) {
lines[i].push_back(word);
}
}
// 处理数据...
return 0;
}
5. 二维数组与矩阵输入
5.1 固定行列的矩阵
已知矩阵的行列数时的处理方法。
示例输入:
code复制2 3
1 2 3
4 5 6
C++处理代码:
cpp复制#include <iostream>
#include <vector>
using namespace std;
int main() {
int rows, cols;
cin >> rows >> cols;
vector<vector<int>> matrix(rows, vector<int>(cols));
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
cin >> matrix[i][j];
}
}
// 处理矩阵...
return 0;
}
5.2 不定行列的矩阵
矩阵行列数未知时的处理方法。
示例输入:
code复制1 2 3
4 5
6 7 8 9
C++处理代码:
cpp复制#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main() {
vector<vector<int>> matrix;
string line;
while (getline(cin, line)) {
istringstream iss(line);
vector<int> row;
int num;
while (iss >> num) {
row.push_back(num);
}
matrix.push_back(row);
}
// 处理矩阵...
return 0;
}
6. 数据结构输入处理
6.1 链表输入
处理链表结构的输入数据。
示例输入:
code复制1 2 3 4 5 -1
C++处理代码:
cpp复制#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr) {}
};
int main() {
int num;
ListNode* dummy = new ListNode(-1);
ListNode* curr = dummy;
while (cin >> num && num != -1) {
curr->next = new ListNode(num);
curr = curr->next;
}
ListNode* head = dummy->next;
// 处理链表...
return 0;
}
6.2 二叉树输入
处理二叉树结构的输入数据。
示例输入:
code复制1 2 3 null 4 5 null
C++处理代码:
cpp复制#include <iostream>
#include <vector>
#include <queue>
#include <string>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
TreeNode* buildTree(vector<string>& nodes) {
if (nodes.empty() || nodes[0] == "null") return nullptr;
TreeNode* root = new TreeNode(stoi(nodes[0]));
queue<TreeNode*> q;
q.push(root);
int i = 1;
while (!q.empty() && i < nodes.size()) {
TreeNode* curr = q.front();
q.pop();
if (i < nodes.size() && nodes[i] != "null") {
curr->left = new TreeNode(stoi(nodes[i]));
q.push(curr->left);
}
i++;
if (i < nodes.size() && nodes[i] != "null") {
curr->right = new TreeNode(stoi(nodes[i]));
q.push(curr->right);
}
i++;
}
return root;
}
int main() {
string line;
getline(cin, line);
istringstream iss(line);
vector<string> nodes;
string node;
while (iss >> node) {
nodes.push_back(node);
}
TreeNode* root = buildTree(nodes);
// 处理二叉树...
return 0;
}
7. 输入输出优化技巧
7.1 提高输入速度
对于大数据量输入,常规方法可能不够快。
C++优化代码:
cpp复制#include <iostream>
#include <cstdio>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int a, b;
while (cin >> a >> b) {
printf("%d\n", a + b);
}
return 0;
}
关键点:
ios::sync_with_stdio(false)关闭与C的同步cin.tie(nullptr)解除cin与cout的绑定- 使用
printf代替cout进一步提速
7.2 处理大整数
当数值超过普通数据类型范围时。
示例输入:
code复制12345678901234567890 98765432109876543210
C++处理代码:
cpp复制#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string addStrings(string num1, string num2) {
string res;
int carry = 0;
int i = num1.size() - 1, j = num2.size() - 1;
while (i >= 0 || j >= 0 || carry) {
int n1 = i >= 0 ? num1[i--] - '0' : 0;
int n2 = j >= 0 ? num2[j--] - '0' : 0;
int sum = n1 + n2 + carry;
res.push_back(sum % 10 + '0');
carry = sum / 10;
}
reverse(res.begin(), res.end());
return res;
}
int main() {
string a, b;
while (cin >> a >> b) {
cout << addStrings(a, b) << endl;
}
return 0;
}
8. 常见问题与调试技巧
8.1 输入缓冲区问题
混合使用cin和getline时可能出现问题。
错误示例:
cpp复制int n;
cin >> n;
string s;
getline(cin, s); // 这里会读取到空行
正确做法:
cpp复制int n;
cin >> n;
cin.ignore(); // 忽略换行符
string s;
getline(cin, s);
8.2 边界条件处理
常见边界情况:
- 空输入
- 单行输入
- 大数据量输入
- 特殊字符输入
测试建议:
- 测试最小输入(如空输入)
- 测试最大规模输入
- 测试特殊字符输入
- 测试异常格式输入
8.3 调试输出技巧
在调试时可以添加调试输出:
cpp复制// 调试二维矩阵
for (const auto& row : matrix) {
for (int num : row) {
cerr << num << " ";
}
cerr << endl;
}
关键点:
- 使用
cerr不影响标准输出 - 调试完成后记得删除或注释掉调试代码
- 可以添加条件编译控制调试输出
9. 实战练习建议
9.1 推荐练习平台
- 牛客网ACM模式练习
- LeetCode自定义输入输出问题
- Codeforces比赛题目
- AtCoder初学者竞赛
9.2 练习题目类型
- 基础输入输出题
- 字符串处理题
- 矩阵/二维数组题
- 树/链表结构题
- 大数据量处理题
9.3 自我检验标准
- 能否正确处理各种输入格式
- 输出格式是否符合要求
- 大数据量下程序是否高效
- 边界条件是否都考虑到
- 代码是否清晰易读
10. 总结与进阶
ACM模式输入输出是算法竞赛和编程面试的基础技能。掌握各种输入情况的处理方法,能够让你更专注于算法逻辑本身,而不是被输入输出问题困扰。建议从简单题目开始练习,逐步提高难度,最终能够熟练处理各种复杂输入场景。
对于想要进一步提高的选手,可以研究:
- 更高效的自定义输入输出方法
- 文件输入输出处理
- 多线程输入处理
- 网络流输入处理
记住,熟练的输入输出处理能力是成为优秀程序员的基础,需要不断练习和积累经验。在实际编程中遇到输入输出问题时,不妨回顾这些基本模式,找到最适合当前场景的解决方案。
