题解:洛谷 P2722 总分Score Inflation

【题目来源】

洛谷:P2722 [USACO3.1] 总分 Score Inflation - 洛谷

【题目描述】

我们可以从几个种类中选取竞赛的题目,这里的一个“种类”是指一个竞赛题目的集合,解决集合中的题目需要相同多的时间并且能得到相同的分数。

你的任务是写一个程序来告诉 USACO 的职员,应该从每一个种类中选取多少题目,使得解决题目的总耗时在竞赛规定的时间里并且总分最大。

【输入】

输入的第一行是用空格隔开的两个整数,分别代表竞赛时间 \(m\) 和题目类 \(n\)

\(2\) 到第 \((n + 1)\) 行,每行两个用空格隔开的整数,第 \((i + 1)\) 行的整数 \(p_i, t_i\) 分别代表解决第 \(i\) 类题得到的分数和需要花费的时间。

既然是某一类题目,那么这一类题目可以重复选择。

【输出】

输出一行一个整数,代表最大的总分。

【输入样例】

300 4
100 60
250 120
120 100
35 20

【输出样例】

605

【核心思想】

  1. 问题分析:给定一个总时间限制 \(m\)\(n\) 类题目,每类题目有固定的得分 \(p_i\) 和耗时 \(t_i\),每类题目可以无限次重复选择。目标是选择若干道题(可重复选同一类),使得总耗时不超过 \(m\) 且总得分最大。这是一个典型的完全背包问题,其中背包容量为 \(m\),物品重量为 \(t_i\),价值为 \(p_i\),且每种物品无限供应。

  2. 算法选择

    • 完全背包动态规划:使用一维 DP 数组 dp[j] 表示容量为 \(j\) 时的最大得分。状态转移方程为 \(dp[j] = \max(dp[j], dp[j - t_i] + p_i)\),遍历容量时从小到大(正序),因为每类题目可以无限取用,允许在当前容量下重复使用同一物品。
    • 复杂度:时间复杂度 \(O(n \times m)\),空间复杂度 \(O(m)\),适合 \(m \le 10000\) 的数据范围。
  3. 关键步骤

    • 读入数据:读取 \(m\)(总时间)和 \(n\)(题目种类数),然后读取每类题目的分数 \(p_i\) 和时间 \(t_i\)(注意代码中数组顺序为 c[i] 为分数,w[i] 为时间)。
    • DP 初始化dp[0] = 0,其余 dp[j] = 0(因为至少可以不选任何题目,得分为 0)。
    • 动态规划转移
      • 外层循环遍历每类题目 \(i\)(1 到 \(n\))。
      • 内层循环遍历容量 \(j\)\(t_i\)\(m\)正序,允许重复选择该类题目)。
      • 更新 dp[j] = max(dp[j], dp[j - t_i] + p_i)
    • 输出dp[m] 即为最大总分。
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \times m)\)\(n\) 是题目种类数,\(m\) 是总时间,均在可接受范围内。
    • 空间复杂度:\(O(m)\),使用一维 DP 数组。
  5. 完全背包的核心思想

    • 与 0-1 背包的区别:0-1 背包每种物品只能选一次,内层容量需倒序遍历;完全背包每种物品可选无限次,内层容量需正序遍历,因为当前状态可以由同一种物品的较小容量状态转移而来。
    • 无后效性\(dp[j]\) 只依赖于当前物品和更小容量的状态,符合动态规划的最优子结构性质。
    • 初始化:这里追求最大得分,所有状态初始化为 0 是合理的,因为可以选择不填满背包。
    • 适用场景:完全背包适用于资源无限、可重复选择的最优化问题,如投资组合、原材料切割等。

【解题思路】

【算法标签】

普及- #完全背包

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int m, n;
int w[10005], c[10005];
int dp[10005];
int main()
{
    cin >> m >> n;  // 输入m和n
    for (int i=1; i<=n; i++) {  // 依次输入n个种类的分数和花费时间
        cin >> c[i] >> w[i];
    }
    for (int i=1; i<=n; i++) {  // 按照完全背包模板填写(滚动数组版本)
        for (int j=w[i]; j<=m; j++) {
            dp[j] = max(dp[j], dp[j-w[i]]+c[i]);
        }
    }
    cout << dp[m] << endl;  //
    return 0;
}

【运行结果】

300 4
100 60
250 120
120 100
35 20
605
posted @ 2026-08-30 09:20  团爸讲算法  阅读(12)  评论(0)    收藏  举报