1. 01背包题目介绍
有 N 件物品和一个容量为 V 的背包,每件物品有各自的价值且只能被选择一次,
要求在有限的背包容量下,装入的物品总价值最大。
思路:
- 迭代n次 枚举每次物品在每个体积的拿法
- 迭代m次 枚举能拿的体积
- 条件判断 如果枚举的体积小于本身的体积那么拿不起 所以我们只能 = f[i-1][j]
- 如果我们能拿的起,那么我们需要和f[i-1][j-v[i]]+w[i]来比较
代码实现(二维背包):
int n, m;
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 = 1; j <= m; j++)
{
当前背包容量装不进第i个物品,则价值等于前i-1个物品
if(j < v[i])
f[i][j] = f[i - 1][j];
能装,需进行决策是否选择第i个物品
else
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
}
cout << f[n][m] << endl;
一维变化:
变化过程:
- 观察动态规划方程可以发现f[i - 1][j], f[i - 1][j - v[i]] + w[i] 都只用到了i-1层而已
- 但是因为我们需要使用到上一层状态所以需要从大到小枚举
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 = m; j >= v[i]; j--)
f[j] = max(f[j], f[j-v[i]]+w[i]);
cout << f[m] << endl;
return 0;
}
2.完全背包题目介绍
有 N 件物品和一个容量为 V 的背包,每件物品有各自的价值且可以任意选择N次,
要求在有限的背包容量下,装入的物品总价值最大。
思路(记忆是可以这么记忆,但是理解过来还是挺复杂的):
- 将01背包的一维表示的第二层循环 反过来
代码实现
int v[N],w[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;
}
多重背包1
题目描述:
也就是将01背包的 每个物品只能选一次换成了 每个物品能选s(给定)次
思路:
从01背包的角度出发,同样的也是选和不选的问题
我们容易发现 多重背包可以分成 1~s种选法
然而每个选法又是选和不选两种状态所以最后还是01背包一样的问题
代码实现
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>=0;j--)
{
for(int k=1;k<=s[i]&&k*v[i]<=j;k++) 这里剪枝优化一下
f[j] = max(f[j],f[j-k*v[i]]+k*w[i]); 这里就是s种 对每种选法选和不选的一个集合
}
}
cout<<f[m];
分组背包问题(其实和多重背包差不多em)
题目大意:
- 给你n组 物品 (也就是引入了一个物品组的概念)
- 然后输入每个物品组的大小(含有物品的多少),以及物品组内每个物品的体积,
- 特定的 每个物品组内 你只能选一个物品
- 最后问你最大价值
思路:
和多重背包差不多,我们将问题化小,
你会发现,这还不是01背包的问题吗,不就是物品组内的物品选和不选吗,
所以我们可以直接 三重循环 就像处理多重背包一样
代码实现:
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(v[i][k]<=j) 装的下的情况下
f[j] = max(f[j],f[j-v[i][k]]+w[i][k]); 这里就是01背包一样的处理了
}
}
}
cout<<f[m]<<endl;