题解:洛谷 P2871 Charm Bracelet

【题目来源】

洛谷:P2871 [USACO07DEC] Charm Bracelet S - 洛谷

【题目描述】

\(N\) 件物品和一个容量为 \(M\) 的背包。第 \(i\) 件物品的重量是 \(W_i\),价值是 \(D_i\)。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

【输入】

第一行:物品个数 \(N\) 和背包大小 \(M\)

第二行至第 \(N+1\) 行:第 \(i\) 个物品的重量 \(W_i\) 和价值 \(D_i\)

【输出】

输出一行最大价值。

【输入样例】

4 6
1 4
2 6
3 12
2 7

【输出样例】

23

【核心思想】

  1. 问题分析:给定 \(N\) 件物品,每件有重量 \(W_i\) 和价值 \(D_i\),背包容量为 \(M\)。每件物品只能选一次,求在总重量不超过 \(M\) 的前提下,能装入背包的最大总价值。这是一个经典的01背包问题。

  2. 算法选择

    • 01背包(一维滚动数组)\(dp[j]\) 表示背包容量为 \(j\) 时的最大价值,逆序遍历容量保证每件物品只选一次
  3. 关键步骤

    • 读取输入\(N, M\)\(N\) 件物品的 \((W_i, D_i)\)
    • 初始化\(dp[0..M] = 0\)
    • 01背包递推\(i\)\(1\)\(N\)):
      • 对于 \(j\)\(M\)\(W_i\) 逆序:
        • \(dp[j] = \max(dp[j],\ dp[j - W_i] + D_i)\)
    • 输出 \(dp[M]\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N \cdot M)\)
    • 空间复杂度:\(O(M)\),一维滚动数组
  5. 01背包的核心思想

    • 选或不选:对于每件物品,只有两种状态——选(占用 \(W_i\) 容量,获得 \(D_i\) 价值)或不选(不占用容量,价值不变)
    • 逆序遍历保证唯一性:容量从大到小遍历,确保 \(dp[j - W_i]\) 是未选第 \(i\) 件物品时的状态,避免同一件物品被重复选取
    • 最优子结构\(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
posted @ 2026-08-28 15:54  团爸讲算法  阅读(1)  评论(0)    收藏  举报