有 N 组物品和一个容量是 V 的背包。
每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数 N,V,用空格隔开,分别表示物品组数和背包容量。
接下来有 N 组数据:
- 每组数据第一行有一个整数 Si,表示第 i 个物品组的物品数量;
- 每组数据接下来有 Si 行,每行有两个整数 vij,wij,用空格隔开,分别表示第 i 个物品组的第 j 个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤100,
0<Si≤100,
0<vij,wij≤100,
输入样例
3 5
2
1 2
2 4
1
3 4
1
4 5
输出样例:
8
区间dp前置题,因为涉及到决策,所以跟多重背包一样是三维表示,不过要比多重背包稍微难一些
我们看道分组背包的循环顺序,其实大部分dp问题决策循环都是放到最后的,在分组背包中决策自然指的是选哪件物品
我们还需要注意一点,若是我们k从0开始循环,那么就不需要单独写出每行继承上一行的状态,因为k等于0的时候f[i][j] = max(f[i][j],f[i-1][j]),这样就会第一时间继承上一行的状态
还有的同学多此一举(就是我)在k循环内更新状态,当然是错糊涂啦,这怎么能对呢?
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<=s[i];k++)
if(j<v[i][k])
f[i][j] = f[i-1][j];
else f[i][j] = max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]);
在for循环内更新状态很有可能导致的结果就是我们在枚举k的时候前面已经更新了状态但是由于后面的物品体积比较大没法更新,所以状态居然倒退到上一行去了???
这显然不对,要继承状态也应该在k循环上面继承
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1010;
int n,m;
int v[N][N],w[N][N],s[N];
int f[N][N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s[i];
for(int j=0;j<s[i];j++)
{
cin>>v[i][j]>>w[i][j]; //读入
}
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
f[i][j]=f[i-1][j]; //不选
for(int k=0;k<s[i];k++)
{
if(j>=v[i][k]) f[i][j]=max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]);
}
}
}
cout<<f[n][m]<<endl;
}
当然这也是可以优化的呀,因为可以看到二维中有一维是i,而每次更新都只会用到上一行数据···
当然了,我们需要逆序更新
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1010;
int n,m;
int v[N][N],w[N][N],s[N];
int f[N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s[i];
for(int j=0;j<s[i];j++)
{
cin>>v[i][j]>>w[i][j];
}
}
for(int i=1;i<=n;i++)
for(int j=m;j>=0;j--)
for(int k=0;k<=s[i];k++)
if(j>=v[i][k]) f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
cout<<f[m]<<endl;
}
要加油啊!!!