一.多重背包带入
题目描述
有 n 件物品和一个容量是 m 的背包。
第 i 件物品的体积是 vi,价值是 wi,使用次数是si。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入描述
第一行两个整数n,m,用空格隔开,分别表示物品种数和背包容积。
接下来有 n行,每行三个整数 vi,wi,si,用空格隔开,分别表示
数据范围
0<n,m≤100
0<vi,wi,si≤100第 i 种物品的体积、价值和数量。
输出描述
输出一个整数,表示最大价值。
样例输入 1
4 5 1 2 3 2 4 1 3 4 3 4 5 2
样例输出 1
10
DP问题我们先来看状态表示,
二维数组的表示,F[i][j]代表到 i 个物品时,当前背包容量为 j 时所能拿到的最大价值。非常容易理解,我们主要考虑一下优化,用一维数组来表示,则用 F [j] 代表当前背包容量为 j时所能拿到的最大价值。第i个物体的体积为v[i],价值为 w [i]。
然后我们就看如何把多重背包转换成01背包与完全背包。
当然,01背包和完全背包转移方程都是
F [j]=max(F [j], F [ j- v [i] ]+ w [i])
那这个无非就是加了一个乘以k也就是一种物品那几个的操作。
上代码:
#include<bits/stdc++.h>
using namespace std;
const int N=10001;
int v[N],w[N],s[N];
int f[N];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>v[i]>>w[i]>>s[i];
}
for(int i=1;i<=n;i++){
for(int j=m;j>=1;j--){
for(int k=1;k<=s[i];k++){
if(k*v[i]>j){
f[j]=f[j];
}else{
f[j]=max(f[j],f[j-v[i]*k]+w[i]*k);//一维数组j从m往前遍历,同时为f[j-v[i]*k]+w[i]*k
}
}
}
}
cout<<f[m]<<endl;
system("pause");
return 0;
}
二.分组背包例题加代码
题目描述
有 n 组物品和一个容量是 m 的背包。
每组物品最多只能使用一个。
第 j 组物品有sj个物品,组内的第i个物品体积是 vi,价值是 wi,
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入描述
第一行有两个整数n,m,用空格隔开,分别表示物品组数和背包容量。
接下来有 n组数据:
-
每组数据第一行有一个整数 Si,表示第i 个物品组的物品数量;
-
每组数据接下来有Si 行,每行有两个整数vij,wij,用空格隔开,分别表示第i 个物品组的第j 个物品的体积和价值;
-
0<n,m≤100
0<Si≤100
0<vij,wij≤100
输出描述
输出一个整数,表示最大价值。
样例输入 1
3 5 2 1 2 2 4 1 3 4 1 4 5
样例输出 1
8
对于这种状态下的dp,我们无非就是对于上面多重背包加了一个组内操作也就是多了一个for循环。
f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);//分组的情况下减去的是v[i][k]。这里的就表示了第i组的v。
上代码:
#include<bits/stdc++.h>
using namespace std;
const int N=10001;
int v[N][N],w[N][N];
int c[N];
int f[N];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>c[i];
for(int j=1;j<=c[i];j++){
cin>>v[i][j]>>w[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=m;j>=1;j--){//一维数组从后往前遍历
for(int k=1;k<=c[i];k++){
if(j<v[i][k]){
f[j]=f[j];
}else{
f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);//分组的情况下减去的是v[i][k]
}
}
}
}
cout<<f[m]<<endl;
system("pause");
return 0;
}
至此,背包问题完结撒花(如果你看过我前几天博客的话)!!!
祝你在dp的路上越走越远!