问题描述
有 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 */