本文分享的必刷题目是从蓝桥云课、洛谷、AcWing等知名刷题平台精心挑选而来,并结合各平台提供的算法标签和难度等级进行了系统分类。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。
欢迎大家订阅我的专栏:算法题解:C++与Python实现!
附上汇总贴:算法竞赛备考冲刺必刷题(C++) | 汇总
【题目来源】
洛谷:P2871 [USACO07DEC] Charm Bracelet S – 洛谷
【题目描述】
有
N
N
N 件物品和一个容量为
M
M
M 的背包。第
i
i
i 件物品的重量是
W
i
W_i
Wi,价值是
D
i
D_i
Di。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
【输入】
第一行:物品个数
N
N
N 和背包大小
M
M
M。
第二行至第
N
+
1
N+1
N+1 行:第
i
i
i 个物品的重量
W
i
W_i
Wi 和价值
D
i
D_i
Di。
【输出】
输出一行最大价值。
【输入样例】
4 6
1 4
2 6
3 12
2 7
【输出样例】
23
【核心思想】
问题分析:给定
N
N
N 件物品,每件有重量
W
i
W_i
Wi 和价值
D
i
D_i
Di,背包容量为
M
M
M。每件物品只能选一次,求在总重量不超过
M
M
M 的前提下,能装入背包的最大总价值。这是一个经典的01背包问题。
算法选择:
- 01背包(一维滚动数组):
d
p
[
j
]
dp[j]
dp[j] 表示背包容量为j
j
j 时的最大价值,逆序遍历容量保证每件物品只选一次
关键步骤:
- 读取输入:
N
,
M
N, M
N,M 和N
N
N 件物品的(
W
i
,
D
i
)
(W_i, D_i)
(Wi,Di) - 初始化:
d
p
[
0..
M
]
=
0
dp[0..M] = 0
dp[0..M]=0 - 01背包递推(
i
i
i 从1
1
1 到N
N
N):- 对于
j
j
j 从M
M
M 到W
i
W_i
Wi 逆序:-
d
p
[
j
]
=
max
(
d
p
[
j
]
,
d
p
[
j
−
W
i
]
+
D
i
)
dp[j] = \\max(dp[j],\\ dp[j – W_i] + D_i)
dp[j]=max(dp[j], dp[j−Wi]+Di)
-
- 对于
- 输出
d
p
[
M
]
dp[M]
dp[M]
时间/空间复杂度:
- 时间复杂度:
O
(
N
⋅
M
)
O(N \\cdot M)
O(N⋅M) - 空间复杂度:
O
(
M
)
O(M)
O(M),一维滚动数组
01背包的核心思想:
- 选或不选:对于每件物品,只有两种状态——选(占用
W
i
W_i
Wi 容量,获得D
i
D_i
Di 价值)或不选(不占用容量,价值不变) - 逆序遍历保证唯一性:容量从大到小遍历,确保
d
p
[
j
−
W
i
]
dp[j – W_i]
dp[j−Wi] 是未选第i
i
i 件物品时的状态,避免同一件物品被重复选取 - 最优子结构:
d
p
[
j
]
dp[j]
dp[j] 仅依赖之前的状态,满足无后效性 - 适用于"有限物品 + 容量约束 + 最大化价值"类经典背包问题
【解题思路】

【算法标签】
#普及- #01背包
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, m, w[4000], d[4000], dp[12890];
int main()
{
cin >> n >> m; // 输入n和m
for (int i=1; i<=n; i++) { // 输入n件无皮的重量和价值
cin >> w[i] >> d[i];
}
for (int i=1; i<=n; i++) { // 01背包的模板(滚动数组版)
for (int j=m; j>=w[i]; j—) {
dp[j] = max(dp[j], dp[j–w[i]]+d[i]);
}
}
cout << dp[m] << endl; // 输出dp[m]
return 0;
}
【运行结果】
4 6
1 4
2 6
3 12
2 7
23


![打卡信奥刷题(3652)用C++实现信奥题 P12076 [OOI 2025] Cute Subsequences-171主机测评](https://www.171host.com/wp-content/uploads/2026/10/20261026055333-6adeeaddd0c48-220x150.png)
