题目:
有 N种物品,背包容量为V,每件2物品可使用无限件。
第i件物品体积为vi,价值为wi。
怎么装使装入背包的物品价值最大。
输入格式:
第一行N,V,物品种数,背包容量。
接下来N行,每行vi,wi。
输出格式:
输出一个整数,表示最大价值。
数据范围:
0<N,V<=1000
0<vi,wi<=1000
输入样例:
4 5
1 2
2 4
3 4
4 5
输出样例:
10
思路:
相比于01背包,不同之处就是每种物品可以取无限多个,那么可以在01背包基础之上多增加一层循环。用来表示可以取从0到k(j/v[i])个物品i。 三层循环。
代码(二维数组):
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N][N];
int main() {
cin >> n >> m;
for (int i = 1;i <= n;i++) cin >> v[i] >> w[i];
for (int i = 1;i <= n;i++) {
for (int j = 0;j <= m;j++) {
for (int k = 0;k * v[i] <= j;k++) {
f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
}
}
cout << f[n][m] << endl;
return 0;
}
优化(二维数组):
思路:
根据推到关系:
f[i , j ] = max( f[i-1,j] , f[i-1,j-v]+w , f[i-1,j-2*v]+2*w , f[i-1,j-3*v]+3*w , .....)
f[i , j-v]= max( f[i-1,j-v] , f[i-1,j-2*v] + w , f[i-1,j-3*v]+2*w , .....)
由上两式,可得出如下递推关系:
f[i][j]=max(f[i,j-v]+w , f[i-1][j])
这样优化了一层循环,少了k。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N][N];
int main() {
cin >> n >> m;
for (int i = 1;i <= n;i++) cin >> v[i] >> w[i];
for (int i = 1;i <= n;i++) {
for (int j = 0;j <= m;j++) {
f[i][j] = f[i - 1][j];
if (j >= v[i]) {
f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]);
}
}
}
cout << f[n][m] << endl;
return 0;
}
优化2:(一维数组)
思路:
和01背包优化方法类似,使用滚动数组。
但观察后发现,完全背包更新每层数组时不仅用到上一层的数组,还用到这一层的数组,因此,需要正序排列
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N];
int main() {
cin >> n >> m;
for (int i = 1;i <= n;i++) cin >> 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]);
}
}
cout << f[m] << endl;
return 0;
}