You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.3 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

## AcWing 3. 完全背包问题

一、题目描述

N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。

i 种物品的体积是 v_i,价值是 w_i

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。

输入格式 第一行两个整数,NV,用空格隔开,分别表示物品种数和背包容积。

接下来有 N 行,每行两个整数 v_i,w_i,用空格隔开,分别表示第 i 种物品的体积和价值。

输出格式 输出一个整数,表示最大价值。

数据范围 0<N,V≤1000 0<v_i,w_i≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例

10

二、完全背包

状态表示:f(i,j) 集合: i是指在前i个物品中进行选择,j是指在总体积不超过j的容量下进行选择。 属性: 求一个最大值。 因为按上面的集合进行选择,每选择一次,就会出现一个结果,我们想求的是这些结果中的最大值。

状态计算01背包不一样,01背包是每一个物品选与不选,完全背包不是这个意思。是可以不选,选择1个,或者选择多个。

i个物品,我们可以选择,也可以放弃,放弃了自然就是f[i-1][j],这个没什么好讲。 如果我们选择了i物品,肯定要带上它的价值v_i,而承担它的重量w_i, 完成了选择它以后,我们接下来可以在前多少个物品中选呢?其实,还是i个,因为每种物品的数量无限啊!所以,选完了i,剩余的表示还是:f[i][j-v_i]

总结一下 二维情况下的状态转移方程

\ 01背包 f[i][j]=max(f[i-1][j],f[i-1][j-v_i]+w_i) 完全背包: f[i][j]=max(f[i-1][j],f[i][j-v_i]+w_i)

这样,再用二维降一维的思路来思考,就得到了完全背包的终极解法:

 for (int i = 1; i <= n; i ++ )
        for (int j = v[i]; j <= m; j ++ ) 
            f[j] = max(f[j], f[j - v[i]] + w[i]); 

三、二维写法

#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int n, m;
int f[N][N];

int main() {
    cin >> n >> m;

    for (int i = 1; i <= n; i++) {
        int v, w;
        cin >> v >> w;
        for (int j = 1; j <= m; j++) {
            f[i][j] = f[i - 1][j];
            if (j >= v)
                f[i][j] = max(f[i][j], f[i][j - v] + w);
        }
    }
    printf("%d\n", f[n][m]);
    return 0;
}

四、一维解法

#include <bits/stdc++.h>

using namespace std;
const int N = 1010;
int n, m;
int f[N];

// 完全背包问题
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        int v, w;
        cin >> v >> w;
        for (int j = v; j <= m; j++)
            f[j] = max(f[j], f[j - v] + w);
    }
    printf("%d\n", f[m]);
    return 0;
}

五、思考

为什么01背包要倒着推,完全背包要顺着推 https://www.cnblogs.com/MyNameIsPc/p/7782700.html