
| 🔭 个人主页:散峰而望 |
|---|
《C语言:从基础到进阶》《编程工具的下载和使用》《C语言刷题》
《C++》《算法竞赛从入门到获奖》《人工智能》《AI Agent》
🎬博主简介



【算法练习】算法练习精选:陶陶摘苹果(基础+升级)、Music Notes、字串变换,你能AC几道?
前言
算法竞赛的学习之路,往往是从一道道经典题目开始的。每一道题背后,都藏着一种独特的解题思想——从最朴素的模拟,到精妙的贪心,再到高效的前缀和 + 二分,以及充满想象力的 BFS 状态空间搜索。
本文精选了四道洛谷上的经典算法题目,由浅入深,带你领略不同算法思想的魅力。无论你是刚入门算法竞赛的新手,还是希望巩固基础的老朋友,相信都能从中有所收获。
话不多说,让我们开始吧!
1. 陶陶摘苹果

算法原理:
模拟,按照题目要求写就行。
参考代码:
#include <iostream>
using namespace std;
int a[15];
int main()
{
for(int i = 1; i <= 10; i++) cin >> a[i];
int n; cin >> n; n += 30;
int ret = 0;
for(int i = 1; i <= 10; i++)
{
if(a[i] <= n)
ret++;
}
cout << ret << endl;
return 0;
}
2. 陶陶摘苹果(升级版)

算法原理:
贪心。
把所有能得到的苹果全部搜集起来,按照力的大小排序,从最小的力开始摘。
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5010;
int n, s;
int a, b;
int cnt;
int t[N];
int main()
{
cin >> n >> s;
cin >> a >> b;
a += b;
for(int i = 1; i <= n; i++)
{
int x, y; cin >> x >> y;
if(x <= a) t[++cnt] = y;
}
sort(t + 1, t + 1 + cnt);
int ret = 0, sum = 0;
for(int i = 1; i <= n; i++)
{
sum += t[i];
if(sum <= s) ret++;
}
cout << ret << endl;
return 0;
}
3. Music Notes S

算法原理:
前缀和 + 二分
- 对所有音阶的敲击次数做一次「前缀和」,那么前缀和数组中每一个位置 f [ i ] f[i] f[i] 表示:第 i i i 个音符「结束的时刻」。
- 那么对于每一次询问 t t t ,我们在前缀和数组中二分出 「 > t >t >t 的第一个位置」的下标,就是结果。
参考代码:
#include <iostream>
using namespace std;
const int N = 5e4 + 10;
int n, q;
int f[N];
int main()
{
cin >> n >> q;
for(int i = 1; i <= n; i++)
{
int x; cin >> x;
f[i] = f[i - 1] + x;
}
while(q--)
{
int t; cin >> t;
int l = 1, r = n;
while(l < r)
{
int mid = (l + r) / 2;
if(f[mid] > t) r = mid;
else l = mid + 1;
}
cout << l << endl;
}
return 0;
}
4. 字串变换

算法原理:
BFS 解决最短路问题。
一个字符串如果能变成另一个字符串,变化的代价是 1 。所以我们可以把所有字符串当成一个点,字符串与字符串之间相当于有一条边长为 1 的边,然后跑一遍 BFS 即可。
这道题的难点在于:
- 如何记录最短路?可以用 unordered_map <string,int > 来记录最短路;
- 如何判断字符串能够变换,以及变换成什么字符串?
- string 里面的 find 能够找出可以变换之后的位置;
- 然后用 substr 完成字符串的拼接操作。
但是要注意,一个字符串可能有多个位置都能转换,所以要多次 find。
参考代码:
#include <iostream>
#include <queue>
#include <unordered_map>
using namespace std;
const int N = 10;
string a, b;
unordered_map<string, int> dist;
int n; // 记录一共有多少个变化规则
string x[N], y[N];
int bfs()
{
if(a == b) return 0;
queue<string> q;
q.push(a);
dist[a] = 0;
while(q.size())
{
string s = q.front(); q.pop();
if(dist[s] >= 10) return -1;
// 变
for(int i = 0; i < n; i++)
{
// x[i] -> y[i]
int pos = 0;
while(s.find(x[i], pos) != -1)
{
pos = s.find(x[i], pos);
// 拼接
string tmp = s.substr(0, pos) + y[i] + s.substr(pos + x[i].size());
pos++;
// s -> tmp
if(dist.count(tmp)) continue;
dist[tmp] = dist[s] + 1;
q.push(tmp);
if(tmp == b) return dist[tmp];
}
}
}
return -1;
}
int main()
{
cin >> a >> b;
while(cin >> x[n] >> y[n]) n++;
int ret = bfs();
if(ret == -1) cout << "NO ANSWER!" << endl;
else cout << ret << endl;
return 0;
}
–
结语
本文通过四道经典算法题目,从模拟到贪心,再到前缀和 + 二分与 BFS 最短路,循序渐进地展示了算法竞赛中常见的解题思路与代码实现。每一道题都不仅仅是代码的堆砌,更是一次思维方式的训练:
- 陶陶摘苹果教会我们:最简单的模拟,往往是最可靠的起点;
- 陶陶摘苹果(升级版) 告诉我们:贪心策略的核心在于排序与选择;
- Music Notes S 展示了:前缀和与二分结合,能将 O ( n ) O(n) O(n) 的查询优化到 O ( log n ) O(\log n) O(logn);
- 字串变换则让我们看到:BFS 不仅能走迷宫,还能在字符串的状态空间中寻找最短路径。
算法学习之路,从来不是一蹴而就的。它需要日复一日的积累,需要面对难题时的坚持,更需要解题后的总结与反思。希望这篇文章能成为你算法旅程中的一块垫脚石。
愿诸君能一起共渡重重浪,终见缛彩遥分地,繁光远缀天。
)

、Music Notes、字串变换,你能AC几道?&spm=1001.2101.3001.5002&articleId=161600101&d=1&t=3&u=1be35bc6f097462caa55e6ab19d291f7)
280

被折叠的 条评论
为什么被折叠?



