背包九讲之二:完全背包问题:一个物品允许选多次

Posted 谢哥在彼方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了背包九讲之二:完全背包问题:一个物品允许选多次相关的知识,希望对你有一定的参考价值。

有 N 件物品和一个容量是 V 的背包。每种物品都有无限件可用。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例
10
 代码如下:
 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 /*
 5 f[i][j]表示只看前i个物品,总体积是j的情况下,总价值最大是多少
 6 result = f[n]f[v]
 7 1.不选第i个物品,f[i][j]=f[i-1][j];
 8 2.选第i个物品,f[i][j]=f[i-1][j-k*v[i]]+k*w[i](v[i]是体积,w[i]是价值,k是物品最大个数)
 9 f[0][0]=0;
10 */
11 const int array_size = 1001;
12 int f[array_size][array_size], v[array_size], w[array_size], N, V;
13 int main() {
14     cin >> N >> V;
15     for (int i = 1; i <= N; ++i) {
16         cin >> v[i] >> w[i];
17         for (int j = 0; j <= V; ++j) {
18             f[i][j] = f[i - 1][j];
19             for (int k = 1; k <= j / v[i]; ++k)
20                 if (j >= k*v[i])
21                     f[i][j] = max(f[i][j], f[i - 1][j - k*v[i]] + k*w[i]);
22         }
23             
24     }
25     cout << f[N][V];
26 }
优化后如下:
#include<iostream>
#include<algorithm>
using namespace std;
const int array_size = 1001;
int f[array_size], v[array_size], w[array_size], N, V;
int main() {
    cin >> N >> V;
    for (int i = 1; i <= N; ++i) {
        cin >> v[i] >> w[i];
        /*
        相当于01背包问题换了j的遍历顺序,结果就是第i轮(前i个物品)
        中,先算f[j-v[i]],再算f[j]
        数学归纳法证明优化后算法成立:
        1、前1个物品中:f[1]=2,f[2]=4,f[3]=6,f[4]=8,f[5]=10,显然f[j]都是正确的。
        2、假设在前i-1个物品中,f[j]都是正确的。
        3、前i个物品中,对于某个j而言,如果最优解包含k个v[i],则一定会枚举到f[j-k*v[i]]
        f[j-k*v[i]]是如何得到的呢?f[j-k*v[i]]=max{f[j-k*v[i]],f[j-k*v[i]-v[i]]+w[i]}
        (由于j正序,f[j-k*v[i]]为前i-1个物品的值,f[j-k*v[i]-v[i]]为前i个物品的值)
        最后会传递到max{f[v[i]],f[0]+w[i]}处。因为f[v[i]]一定正确(2中已假设前i-1个物品
        中的f[j]全都正确),f[0]一定正确(=0),w[i]一定正确,所以max{f[v[i]],f[0]+w[i]}
        一定正确=>f[j-k*v[i]]一定正确=>f[j]一定正确。
        综上,证明成立。
        */
        for (int j = v[i]; j <= V; ++j)
            f[j] = max(f[j], f[j -v[i]] + w[i]);
            
    }
    cout << f[V];
}
/*
若是要求物品恰好装满背包时的最大价值,只需
初始化时将f[0]置0,f[1]-f[V]都置-INF就可以了。
确保所有状态都是由f[0]转移过来。
*/

以上是关于背包九讲之二:完全背包问题:一个物品允许选多次的主要内容,如果未能解决你的问题,请参考以下文章

第二讲 完全背包问题(对背包九讲的学习)

动态规划——背包问题python实现(01背包完全背包多重背包)

动态规划 之背包问题(九讲)

模板背包

背包九讲

背包九讲