背包九讲之一:01背包问题:一个物品只允许选一次

问题描述
有 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
输出样例
8
使用二维数组,代码如下:
 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 /*
 5 f[i][j]表示只看前i个物品,总体积是j的情况下,总价值最大是多少
 6 result = max{f[n][0-v]}
 7 1.不选第i个物品,f[i][j]=f[i-1][j];
 8 2.选第i个物品,f[i][j]=f[i-1][j-v[i]]+w[i](v[i]是体积,w[i]是价值)
 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 i = 1; i <= N; ++i)
18         for (int j = 0; j <= V; ++j) {
19             f[i][j] = f[i - 1][j];
20             if(j>=v[i])
21                 f[i][j] = max(f[i-1][j], f[i - 1][j - v[i]] + w[i]);
22         }
23     /*
24     不能直接使用
25     for (int i = 1; i <= N; ++i)
26         for (int j = v[i]; j <= V; ++j)
27             f[i][j] = max(f[i-1][j], f[i - 1][j - v[i]] + w[i]);
28     因为漏掉了j<v[i]时,一定满足f[i][j]=f[i-1][j]的情况。
29     例如i=1,j=2,v[1]=1,w[1]=3时,2>=v[1],f[1][2]=3
30     下轮i=2,j=2,v[2]=3,w[2]=4时,2<v[2],f[2][2]=0,出错。应当f[2][2]=f[1][2]=3
31     */
32     cout << f[N][V]; //表示的是物品个数<=N,体积<=V的最大价值
33 }
优化后使用一维数组,代码如下:
 
 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 const int array_size = 1001;
 5 int f[array_size], v[array_size], w[array_size], N, V;
 6 int main() {
 7     cin >> N >> V;
 8     for (int i = 1; i <= N; ++i)
 9         cin >> v[i] >> w[i];
10     for (int i = 1; i <= N; ++i)
11         /*
12         1、此处若j正序,在第i轮(前i个物品)中,由于j-v[i]<j,先算的是f[j-v[i]],
13         再算f[j]。则f[j-v[i]]相当于上例中的f[i][j-v[i]]。
14         2、若j倒叙,在第i轮中,先算f[j],再算f[j-v[i]]。则f[j-v[i]]
15         相当于上例中的f[i-1][j-v[i]]。故使用倒叙。
16         */
17         for (int j = V; j >= v[i]; --j)
18             f[j] = max(f[j], f[j - v[i]] + w[i]);
19     /*
20     迭代过程中并未考虑上例红字部分的问题。因为第i轮中的f[j]
21     未重新赋值前天然就是第i-1轮中的f[j]
22     */
23     cout << f[V];//f[V]表示的是体积<=V的最大价值
24 }
25 /*
26 若是要求物品恰好装满背包时的最大价值,只需
27 初始化时将f[0]置0,f[1]-f[V]都置-INF就可以了。
28 确保所有状态都是由f[0]转移过来。
29 */

猜你喜欢

转载自www.cnblogs.com/xiehuazhen/p/12453737.html