1. 程序设计竞赛入门:C++基础语法精要
作为程序设计竞赛的入门选手,掌握C++基础语法是迈向成功的第一步。本章将带你深入理解《深入浅出程序设计竞赛(基础篇)》第二章的12个经典练习,这些题目看似简单,却蕴含着程序设计竞赛中常见的基础思维模式和解题技巧。
在竞赛编程中,我们经常需要处理各种基础问题:从简单的数学运算到字符处理,从变量交换到时间计算。这些基础能力就像建筑的地基,决定了你未来能走多远。让我们通过这12个练习,逐步构建起扎实的编程基础。
提示:虽然这些题目看起来简单,但每个题目都经过精心设计,包含了竞赛编程中常见的陷阱和技巧。建议不要只是复制代码,而是理解每个实现的背后逻辑。
2. 基础数学运算与类型转换
2.1 速度差计算问题
第一个练习(2-1)展示了如何计算两个物体以不同速度移动时的相遇时间:
cpp复制#include <iostream>
using namespace std;
int main() {
int v_a = 5, v_yao = 8, distance = 100;
double delta, ans;
delta = v_yao - v_a;
ans = distance / delta;
cout << ans << endl;
return 0;
}
这里有几个关键点需要注意:
- 变量命名要有意义,如v_a表示A的速度,v_yao表示另一个物体的速度
- 使用double类型存储结果以保证精度
- 基础物理公式的应用:时间=距离/速度差
2.2 字符与ASCII码的转换
练习2-2展示了C++中字符处理的本质:
cpp复制#include <iostream>
using namespace std;
int main() {
int ans1;
char ans2;
ans1 = 'M' - 'A' + 1;
ans2 = 'A' + 18 - 1;
cout << ans1 << endl;
cout << ans2 << endl;
return 0;
}
这个例子揭示了C++中字符处理的本质:
- char类型实际上是8位整数
- 字符运算实际上是ASCII码的运算
- 可以通过算术运算实现字符转换
注意:在竞赛编程中,这种字符与ASCII码的转换技巧经常用于各种编码和解码问题。
3. 数学公式实现与宏定义
3.1 球体体积计算
练习2-3展示了如何使用数学公式和宏定义:
cpp复制#include<iostream>
#include<cmath>
#define PI 3.141593
using namespace std;
int main() {
int r1 = 4, r2 = 10;
double V, l;
V = 4.0 / 3 * PI * (pow(r1, 3) + pow(r2, 3));
l = pow(V, 1.0 / 3);
cout << (int)l << endl;
return 0;
}
关键学习点:
- 宏定义的正确使用方法(注意不能使用等号)
- 数学库函数pow的使用
- 类型转换(double转int)
3.2 二次方程求解
练习2-4展示了数学公式的直接实现:
cpp复制#include <iostream>
#include <cmath>
#define PI 3.141593
using namespace std;
int main() {
double a = 1, b = -100, c = 2400;
double delta, ans;
delta = pow(b, 2) - 4 * a * c;
ans = (-b + sqrt(delta)) / (2 * a);
cout << 110 - int(ans + 0.5) << endl;
return 0;
}
这里有几个竞赛编程的实用技巧:
- 二次方程求根公式的直接应用
- 使用int(ans + 0.5)实现四舍五入
- 数学公式的精确实现
4. 输入输出处理与优化
4.1 基础输入输出
练习2-5展示了最简单的输入输出处理:
cpp复制#include <iostream>
using namespace std;
int main() {
int t, n;
cin >> t >> n;
cout << t * n << endl;
return 0;
}
虽然简单,但需要注意:
- 输入的顺序要与题目要求一致
- 输出格式要完全符合题目要求
4.2 字符大小写转换
练习2-6展示了字符处理的另一种应用:
cpp复制#include <iostream>
using namespace std;
int main() {
char ch, ans1, ans2;
cin >> ch;
ans1 = ch - 'a' + 'A'; // 小写转大写
ans2 = ch - 'A' + 'a'; // 大写转小写
cout << ans1 << endl << ans2;
return 0;
}
这个例子展示了:
- 大小写字母ASCII码的规律
- 字符转换的数学方法
- 如何同时处理大小写转换
5. 算法思维与优化技巧
5.1 数字反转的多种解法
练习2-7展示了同一问题的多种解法:
cpp复制// 解法一:暴力分解
double p;
int q, a, b, c, d;
cin >> p;
q = int(p * 10);
a = q / 1000;
b = (q / 100) % 10;
c = (q / 10) % 10;
d = q % 10;
cout << d << "." << c << b << a << endl;
// 解法二:字符处理
char a, b, c, dot, d;
cin >> a >> b >> c >> dot >> d;
cout << d << dot << c << b << a << endl;
// 解法三:C语言风格
char a, b, c, d;
scanf("%c%c%c.%c", &a, &b, &c, &d);
printf("%c.%c%c%c", d, c, b, a);
这个练习特别有价值,因为它展示了:
- 同一问题的多种解决思路
- 不同方法的时间复杂度和空间复杂度
- C++和C风格的输入输出对比
5.2 时间计算问题
练习2-10展示了时间计算的正确方法:
cpp复制int a, b, c, d, e, f, delta;
scanf("%d%d%d%d", &a, &b, &c, &d);
delta = (60 * c + d) - (60 * a + b);
e = delta / 60;
f = delta % 60;
printf("%d %d\n", e, f);
关键技巧:
- 将时间统一转换为分钟数进行计算
- 避免直接对小时和分钟分别计算
- 使用除法和取模运算转换回小时和分钟
6. 实用技巧与常见错误
6.1 变量交换的经典方法
练习2-9展示了变量交换的经典三变量法:
cpp复制int a, b, t;
scanf("%d%d", &a, &b);
t = a;
a = b;
b = t;
printf("%d %d\n", a, b);
虽然简单,但需要注意:
- 临时变量的使用
- 交换的顺序
- 在实际竞赛中,有时可以使用异或运算实现无临时变量的交换
6.2 浮点数精度处理
练习2-11展示了分数计算的优化方法:
cpp复制// 一般解法
double total_score, homework_score, exam_score, final_score;
cin >> homework_score >> exam_score >> final_score;
total_score = homework_score * 0.2 + exam_score * 0.3 + final_score * 0.5;
cout << total_score << endl;
// 优化解法
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
printf("%d", a * 2 / 10 + b * 3 / 10 + c * 5 / 10);
这个例子告诉我们:
- 浮点数运算可能存在精度问题
- 有时可以使用整数运算避免浮点数问题
- 根据题目要求选择合适的数据类型
6.3 时间格式化输出
练习2-12展示了时间计算和格式化输出的技巧:
cpp复制int s, v;
cin >> s >> v;
int t_walk = ceil(1.0 * s / v);
int from_zero = 60 * (24 + 8) - t_walk;
int hh = (from_zero / 60) % 24;
int mm = from_zero % 60;
printf("%02d:%02d\n", hh, mm);
关键点:
- ceil函数的使用(向上取整)
- 时间计算的模运算技巧
- printf的格式化输出(%02d确保两位数显示)
7. 竞赛编程的实用建议
通过这12个基础练习,我们可以总结出一些竞赛编程的实用建议:
- 理解问题本质:每个问题背后都有其数学或逻辑本质,理解这一点才能写出高效代码
- 多种解法比较:尝试用不同方法解决同一问题,比较它们的优缺点
- 注意边界条件:特别是涉及除法、取模等运算时,要考虑边界情况
- 优化输入输出:在大型竞赛中,输入输出效率可能影响整体性能
- 代码可读性:良好的变量命名和代码结构有助于调试和后期维护
在实际竞赛中,这些基础技能将组合成更复杂的算法和数据结构应用。建议初学者反复练习这些基础题目,直到能够不假思索地写出正确代码。