算法竞赛入门经典_学习笔记_各例题和训练源文件
第01章_程序设计入门
Example_0108_变量交换_方法1_三变量法.cpp
Example_0109_变量交换_方法2_不借助第三变量.cpp
Example_0111_鸡兔同笼_数学二元一次方程.cpp
Example_0113_三整数排序_逐情况列举法.cpp
Example_0114_三整数排序_比较交换法.cpp
Example_0115_三整数排序_最值计算法.cpp
Exercise_0101_平均数(average)_CPP版.cpp
Exercise_0101_平均数(average)_C语言版.cpp
Exercise_0102_温度(temperature).cpp
Exercise_0103_连续和(sum).cpp
Exercise_0104_正弦和余弦(sincos).cpp
Exercise_0105_距离(distance).cpp
Exercise_0106_偶数(odd)_利用整型数据法.cpp
Exercise_0106_偶数(odd)_求余运算法.cpp
Exercise_0107_打折(discount).cpp
Exercise_0108_绝对值(abs).cpp
Exercise_0109_三角形(triangle).cpp
Exercise_0110_闰年(leapYear).cpp
Thinking_0101_计算int型整数的最小值和最大值.cpp
// Example_0108_变量交换_方法1_三变量法.cpp /** * 交换变量的第一种经典方法: * 通过多申请一个变量,然后临时存储,交换。 * 这种方法可以理解成:刚刚被临时存储值的变量,可以被赋值。 * 如:刚刚 t = a; 那么此时的变量a已经被临时变量保存了,那么就可以进行变化了。 * 现在的目标是将a与b交换,即然现在a可以变化,那就可以直接存放b的值。 * 最后,即然b的值已经被拿过去了,为达交换目的,现在a的值可以从t那么取回放到b处了。 **/ #include <iostream> int main() { int a, b, t; std::cin >> a >> b; t = a; // 开始交换 a = b; b = t; // 交换完毕 std::cout << a << b << std::endl; return 0; }
// Example_0109_变量交换_方法2_不借助第三变量.cpp /** * 交换变量的第二种经典方法:不用借助第三变量就可以实现两值交换了。 * 注意:这方法不推介,因为适用范围比较窄,只有定义了加减法数据类型才可这样做。 * 这种方法可以理解成:相加得总量,相减换变量,总量再得分量; * 开始交换: * 第一步: a = a + b; * 此时,将a变量变为原来两变量的总和; * 第二步: b = a - b; * 记住,此时的a,已是总和,那么总和减去原来的b的值,得到的就是原来的a的值, * 所以在这一步当中,已经实现了将原a值赋值到b变量中。 * 第三步: a = a - b; * 此时,右边的a仍是总和,右边的b的值已是原来的a值,所以要将a变量变为原来的b值, * 只需要将总和减去原a值就得出原b值了,这一步,实现了将a变量的值变为b变量。 **/ #include <iostream> int main() { int a, b; std::cin >> a >> b; a = a + b; // 开始交换 b = a - b; a = a - b; // 交换完毕 std::cout << a << b << std::endl; return 0; }
// Example_0111_鸡兔同笼_数学二元一次方程.cpp /** * 题目名称:鸡兔同笼 * 题目描述: * 已知鸡和兔的总数量为n,总腿数为m。输入n和m依次输出鸡的数目和兔的数目。 * 如果无解,则输出“No answer”(不要引号)。 * 样例输入: 14 32 * 样例输出: 12 2 * 样例输入: 10 16 * 样例输出: No answer **/ /** * 题目分析: * 此题可以理解为解二元一次方程的数学题,鸡的数目为a, 兔的数目为b。 * 则: 4*b+2*a= m, a+b=n,解得:a=(4n-m)/2, b=n-a. * 此外:考虑无解的情况,1:总腿数需要满足为偶数,2:鸡兔数目为正数。 **/ #include <iostream> int main() { int n, m; while(std::cin >> n >> m) { int a, b; a = (4 * n - m) / 2; b = n - a; if (m % 2 != 0 || a < 0 || b < 0) { std::cout << "No answer\n"; continue; } else { std::cout << a << " " << b << std::endl; } } return 0; }
// Example_0113_三整数排序_逐情况列举法.cpp /** * 题目名称:三整数排序 * 题目描述:输入3个整数,从小到大排序后输出。 * 样例输入:26 78 12 * 样例输出:12 26 78 **/ /** * 排序方法,逐情况列举,这种方法有点笨,不过也是很容易想出的方法。 * 如果有三个整数,那么,它就会有3*2*1+1种情况, * 第一个数可取3种情况,最大,最小,中等。 * 那么第二个数就是,剩下的2种情况。 * 第三个数,没有其它可选,剩下1种情况。 **/ #include <stdio.h> int main() { int a, b, c; scanf("%d%d%d", &a, &b, &c); if (a <= b && b <= c) printf("%d %d %d\n", a, b, c); else if(a <= c && c <= b) printf("%d %d %d\n", a, c, b); else if(b <= c && c <= a) printf("%d %d %d\n", b, c, a); else if(b <= a && a <= c) printf("%d %d %d\n", b, a, c); else if(c <= a && a <= b) printf("%d %d %d\n", c, a, b); else if(c <= b && b <= a) printf("%d %d %d\n", c, b, a); return 0; }
// Example_0114_三整数排序_比较交换法.cpp /** * 题目名称:三整数排序 * 题目描述:输入3个整数,从小到大排序后输出。 * 样例输入:26 78 12 * 样例输出:12 26 78 **/ /** * 排序方法,比较交换法。 * 这种方法,将会改变原变量的数值,同时,在交换时,也用到了三变量法。 * 这里的比较只需要三次,第一次是将第一个数与第二个数比较,将较小值(交换)移到第一个数上。 * 第二次是将第一个数与第三个数比较,将较小值(交换)移到第一个数上,这样一来,第一个数就是最小值了。 * 接下来就只剩下两个需要确定的数,再将第二个数与第三个数进行比较,将较小值移至第二个数上(交换)。 * 此时,已完成了三数的排序,总思路是,先确定最小值,然后确定较小值,最后确定最大值。 **/ #include <iostream> using std::cin; using std::cout; using std::endl; int main() { int a, b, c, t; cin >> a >> b >> c; if (a > b) { t = a; a = b; b = t;} if (a > c) { t = a; a = b; b = t;} if (b > c) { t = a; a = b; b = t;} cout << a << " " << b << " " << c << endl; return 0; }
// Example_0115_三整数排序_最值计算法.cpp /** * 题目名称:三整数排序 * 题目描述:输入3个整数,从小到大排序后输出。 * 样例输入:26 78 12 * 样例输出:12 26 78 **/ /** * 排序方法,最值计算法。 * 这种方法,主要思路,筛选最大值和最小值,然后,得出中间值,最后,直接输出。 * 借用的变量可能比较多,三个。 * 首先,使用第一个变量作标记(记录),通过逐个比较,得出最大值; * 然后,使用第二个变量作标记(记录),通过逐个比较,得出最小值; * 最后,由总数值减去两最值,就可得到中值了。 **/ #include <iostream> using std::cin; using std::cout; using std::endl; int main() { int a, b, c; int max, min, mid; cin >> a >> b >> c; max = a; min = a; if (b > max) max = b; if (c > max) max = c; if (b < min) min = b; if (c < min) min = c; mid = a + b + c - max - min; cout << max << " " << mid << " " << min << endl; return 0; }
// Exercise_0101_平均数(average)_CPP版.cpp /** * 题目要求:输入3个整数,输出它们的平均值,保留3位小数。 **/ #include <iostream> using std::cin; using std::cout; int main() { double a, b, c; cin >> a >> b >> c; cout.precision(3); // 此句将对以后的cout语句都有效,默认情况下会输出六位小数 cout << (a + b + c) / 3 << std::endl; system("pause"); return 0; }
// Exercise_0101_平均数(average)_C语言版.cpp /** * 题目要求:输入3个整数,输出它们的平均值,保留3位小数。 **/ #include <stdio.h> int main() { double a, b, c; // 注意: lf代表double scanf("%lf%lf%lf", &a, &b, &c); double result = (a + b + c) / 3; printf("%-.3lf\n", result); return 0; }
// Exercise_0102_温度(temperature).cpp /** * 题目要求:输入华氏温度f,输出对应的摄氏温度c,保留3位小数。 * 提示:c = 5 * (f - 32) / 9; **/ #include <iostream> using std::cin; using std::cout; int main() { double f; cin >> f; cout.precision(3); cout << 5 * (f - 32) / 9 << std::endl; return 0; }
// Exercise_0103_连续和(sum).cpp /** * 题目要求:输入正整数n,输出 1+2+...+n的值。 **/ #include <iostream> using std::cin; using std::cout; int main() { long n; cin >> n; long s = 0; ++n; for ( int i = 1; i < n; ++i) { s += i; } cout << s << std::endl; return 0; }
// Exercise_0104_正弦和余弦(sincos).cpp /** * 题目要求:输入正整数n(n<360),输出n度的正弦、余弦函数值。 * 提示:可使用数学函数。 **/ #include <iostream> #include <cmath> using std::cin; using std::cout; int main() { double n; cin >> n; cout << sin(n) << " " << cos(n) << std::endl; return 0; }
// Exercise_0105_距离(distance).cpp /** * 题目要求:输入4个浮点数x1, y1, x2, y2, 输出平面坐标系中点(x1, y1)到点(x2, y2)的距离。 **/ #include <iostream> #include <cmath> using std::cin; using std::cout; int main() { float x1, x2, y1, y2; cin >> x1 >> y1 >> x2 >> y2; // abs求绝对值 // pow求次方 // sqrt开平方 cout << sqrt(pow(abs(x1 - x2), 2) + pow(abs(y1 - y2), 2)) << std::endl; return 0; }
// Exercise_0106_偶数(odd)_利用整型数据法.cpp /** * 题目要求:输入一个整数,判断它是否为偶数。 * 如果是,则输出“yes”,否则输出“no”。 * 提示:可用多种方法判断。 **/ #include <iostream> using std::cin; using std::cout; using std::endl; int main() { int number; cin >> number; // 若非偶数,则除以2时会失真,再乘以2时则不会等于本身 if (number / 2 * 2 == number){ cout << "yes" << endl; } else{ cout << "no" << endl; } return 0; }
// Exercise_0106_偶数(odd)_求余运算法.cpp /** * 题目要求:输入一个整数,判断它是否为偶数。 * 如果是,则输出“yes”,否则输出“no”。 * 提示:可用多种方法判断。 **/ #include <iostream> using std::cin; using std::cout; using std::endl; int main() { int number; cin >> number; // 若为偶数,则除以2时无余数 if (number % 2 == 0){ cout << "yes" << endl; } else{ cout << "no" << endl; } return 0; }
// Exercise_0107_打折(discount).cpp /** * 题目要求:一件衣服95元,若消费满300元,可打八五折。 * 输入购买衣服件数,输出需要支付的金额(单位:元),保留两位小数。 **/ #include <iostream> using std::cin; using std::cout; using std::endl; int main() { const double discount = 0.85; const double minConsume = 300.0; const double singleConsume = 95.0; double number; cin >> number; double sum = number * singleConsume; if (minConsume < sum){ sum *= discount; } cout.precision(2); cout.setf(std::ios_base::fixed, std::ios_base::floatfield); cout << sum << endl; return 0; }
// Exercise_0108_绝对值(abs).cpp /** * 题目要求:输入一个浮点数,输出它的绝对值,保留两位小数。 * 不能使用库函数math或cmath **/ #include <iostream> using std::cin; using std::cout; using std::endl; int main() { float number; cin >> number; if (0 > number){ number = 0 - number; } cout << number << endl; return 0; }
// Exercise_0109_三角形(triangle).cpp /** * 题目要求:输入三角形三边长度值(均为正整数),判断它是否能为直角三角形的三个边长。 * 如果可以,则输出“yes”,如果不能,则输出“no”。 * 如果根本无法构成三角形,则输出“not a triangle”。 **/ /** * 题目分析: * 对于这题,可以先判断是否三角形,然后再进行下一步的判断,判断是否能构成直接三角形。 * 判断三角形:两边之和大于第三边即可判断。 * 判断是否直角三角形:可以用勾股定理,不过前提得先判断出最大边是哪一条。 **/ #include <iostream> using std::cin; using std::cout; using std::endl; int main() { long a, b, c; cin >> a >> b >> c; // 下面开始判断是否能成为三角形 if (a + b < c || a + c < b || b + c < a){ cout << "not a triangle" << endl; return 0; } // 下面先找出最大边,并将最大边交换放到变量a处存放 long max = a; if (max < b){max = b; b = a; a = max;} if (max < c){max = c; c = a; a = max;} // 下面开始使用勾股定理判断是否能成为直角三角形 if (a * a == b * b + c * c){ cout << "yes" << endl; } else{ cout << "no" << endl; } return 0; }
// Exercise_0110_闰年(leapYear).cpp /** * 题目要求:输入年份,判断是否闰年。 * 如果是,则输出“yes”,否则输出“no”。 **/ /** * 题目分析:首先得知道常识是:平年365天,闰年366天。 * 计算方法:公历闰年的精确计算方法(按一回归年365天5小时48分45.5秒) * ① 普通年能被4整除且不能被100整除的为闰年。(如2004年就是闰年,1901年不是闰年) * ② 世纪年能被400整除的是闰年。(如2000年是闰年,1900年不是闰年) * ③ 对于数值很大的年份,这年如果能整除3200,并且能整除172800则是闰年。 * 如172800年是闰年,86400年不是闰年(因为虽然能整除3200,但不能整除172800)(此按一回归年365天5h48'45.5''计算)。 * 程序编写思路:从大到小判断。 * ① 先判断数值是否满足第3个条件(数值很大的年份),因为这样判断可以先满足大的数值的条件,避免小数值条件的多余判断。 * ② 再判断数值是否满足第2个条件(世纪年),判断是否闰年。 * ③ 最后使用普通年的判断方法以判断是否闰年。 **/ #include <iostream> using std::cin; using std::cout; using std::endl; int main() { long year; cin >> year; // 数值很大的年份 if ( year > 172800){ if (0 == year % 3200){ cout << "yes" << endl; } else{ cout << "no" << endl; } } // 世纪年 else if(0 == year % 100){ if(0 == year % 400){ cout << "yes" << endl; } else{ cout << "no" << endl; } } // 普通年 else{ if (0 == year % 4){ cout << "yes" << endl; } else{ cout << "no" << endl; } } return 0; }
// Thinking_0101_计算int型整数的最小值和最大值.cpp /** * 计算方法: * 最小值:当int型的数据到了最小值时,然后再减1(即越界时),它会变成正数, * 如果此时再将此数值加1,就可以知道这最小值是多少了。 * 最大值:同理,当int型的数据到了最大值时,然后再加1(即越界时),它会变成负数, * 如果此时再将此数值减1,就可以知道这最大值是多少了。 **/ #include <iostream> int int_min() { int n = 0; while(0 >= n) { --n; } ++n; return n; } int int_max() { int n = 0; while(n >= 0) { ++n; } --n; return n; } int main() { int min = int_min(); int max = int_max(); std::cout << min << " " << max << std::endl; system("pause"); return 0; }