前言
✨本博客讲解 蓝桥杯C/C++ 备赛所涉及算法知识,此博客为第五讲:数学【例/习题】
本篇博客所包含习题有:
👊买不到的数目
👊蚂蚁感冒
👊饮料换购
博客内容以题代讲,通过讲解题目的做法来帮助读者快速理解算法内容,需要注意:学习算法不能光过脑,更要实践,请读者务必自己敲写一遍本博客相关代码!!!
买不到的数目
来源:第四届蓝桥杯省赛C++A组,第四届蓝桥杯省赛JAVAC组
题目要求
题目描述:
小明开了一家糖果店。
他别出心裁:把水果糖包成 4 颗一包和 7 颗一包的两种。
糖果不能拆包卖。
小朋友来买糖的时候,他就用这两种包装来组合。
当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。
你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是 17 。
大于17的任何数字都可以用 4 和 7 组合出来。
本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。
输入格式:
两个正整数 n , m表示每种包装中糖的颗数。
输出格式:
一个正整数,表示最大不能买到的糖数。
数据范围:
2≤n,m≤1000,
保证数据一定有解。
输入样例:
4 7
输出样例:
17
思路分析
小学奥数题,如果你知道公式那么这个题就直接输出即可,如果不知道公式,那么就可以通过打表的方式去尝试是否能看出规律,下面附上打表的代码:
#include <iostream> #include <cstring> #include <algorithm> using namespace std; bool dfs(int m, int p, int q) { if (!m) return true; if (m >= p && dfs(m - p, p, q)) return true; if (m >= q && dfs(m - q, p, q)) return true; return false; } int main() { int p, q; cin >> p >> q; int res = 0; for (int i = 0; i <= 1000; i ++ ) if (!dfs(i, p, q)) res = i; cout << res << endl; return 0; } /* 2 3 1 3 4 5 3 5 7 4 7 17 3 7 11 5 6 19 */
上面就是我们的打表数据,好了现在你要做的就是从打表中发现规律:res=n∗m−(n+m)
代码
#include <iostream> #include <cstring> #include <algorithm> using namespace std; int main() { int n, m; cin >> n >> m; cout << n * m - (n + m) << endl; return 0; }
蚂蚁感冒
来源:第五届蓝桥杯省赛C++A/B组
题目要求
题目描述:
长 100厘米的细长直杆子上有 n 只蚂蚁。
它们的头有的朝左,有的朝右。
每只蚂蚁都只能沿着杆子向前爬,速度是 1 厘米/秒。
当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。
这些蚂蚁中,有 1 只蚂蚁感冒了。
并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。
请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。
输入格式:
第一行输入一个整数 n , 表示蚂蚁的总数。
接着的一行是 n 个用空格分开的整数Xi,Xi的绝对值表示蚂蚁离开杆子左边端点的距离。
正值表示头朝右,负值表示头朝左,数据中不会出现 0 值,也不会出现两只蚂蚁占用同一位置。
其中,第一个数据代表的蚂蚁感冒了。
输出格式:
输出 1 个整数,表示最后感冒蚂蚁的数目。
数据范围:
1<n<50,
0<∣Xi∣<100
输入样例1:
3
5 -2 8
输出样例1:
1
输入样例2:
5
-10 8 -20 12 25
输出样例2:
3
思路分析
题目中比较复杂的操作就是两只蚂蚁碰面之后会立刻掉头,这个操作在代码中该如何实现呢?其实是完全可以忽略的,因为每只蚂蚁的速度大小都是相同的,并且碰面的瞬间会发生感染,且碰面不会有时间的消耗,所以我们两只蚂蚁碰面传染反转方向完全可以看成两只蚂蚁碰面传染并且按照原方向继续行走,因为不管有没有反转方向它们的现实含义都是相同的,本题最难的就是想到这一点去简化题目,后面的操作就很简单了:
如果感染蚂蚁朝右走:
- 该蚂蚁右边向左走的蚂蚁全部感染 √
- 该蚂蚁右边向右走的蚂蚁不会感染 ×
- 该蚂蚁左边向左走的蚂蚁不会被感染 ×
- 该蚂蚁左边向右走的蚂蚁:
- 如果该蚂蚁有右边往左走的蚂蚁则全感染 √
- 如果该蚂蚁没有右边往左走的蚂蚁则0感染 ×
我们现在用右左代表右边往左走,左右代表左边往右走
结论:感染蚂蚁朝右走时,感染数为:
- 右边有向左走的蚂蚁: 右左+左右+1
- 右边没有向左走的蚂蚁: 1
如果感染蚂蚁朝左走:
和上述分析同理有结论:
- 左边有向右走的蚂蚁: 左右+右左+1
- 左边没有向右走的蚂蚁: 1
代码
#include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N = 55; int a[N]; int main() { int n; cin >> n; for (int i = 0; i < n; i ++ ) cin >> a[i]; //计算左右和右左的数量 int left = 0, right = 0; //左右,右左的蚂蚁数 for (int i = 1; i < n; i ++ ) { if (abs(a[i]) > abs(a[0]) && a[i] < 0) right ++; if (abs(a[i]) < abs(a[0]) && a[i] > 0) left ++; } if ((a[0] > 0 && right) || (a[0] < 0 && left)) cout << left + right + 1 << endl; else cout << 1 << endl; return 0; }
饮料换购
来源:第六届蓝桥杯省赛C++A/C组,第六届蓝桥杯省赛JAVAB组
题目要求
题目描述:
乐羊羊饮料厂正在举办一次促销优惠活动。乐羊羊 C型饮料,凭 3 个瓶盖可以再换一瓶C型饮料,并且可以一直循环下去(但不允许暂借或赊账)。
请你计算一下,如果小明不浪费瓶盖,尽量地参加活动,那么,对于他初始买入的 n 瓶饮料,最后他一共能喝到多少瓶饮料。
输入格式:
输入一个整数 n ,表示初始买入的饮料数量。
输出格式:
输出一个整数,表示一共能够喝到的饮料数量。
数据范围:
0<n<10000
输入样例:
100
输出样例:
149
思路分析
经典小学数学题,不做过多解释
代码
#include <iostream> #include <cstring> #include <algorithm> using namespace std; int main() { int n; cin >> n; int res = n; while (n >= 3) { res += n / 3; n = n / 3 + n % 3; } cout << res << endl; return 0; }