背包详谈
问题:在n种物品中选取若干件放在空间为m的背包里,每种物品的体积为w1,w2,…,wn,与之相对应的价值为v1,v2,…,vn.求解怎么装物品可使背包里物品总价值最大
- 01背包——每种物品只有两种性质:选或不选
- 完全背包——每种物品有无限个
—————————————我是分割线—————————————————
dp[i][j]表示前i个物品达到的重量j所达到的最高价值
则dp[n][m]为所求的答案
- 01背包: 我们已经知道对于第i个物品,只有两个性质,选或不选;如果选的话那么dp[i][j]为dp[i - 1][j - w[i]] + v[i],如果不选的话那么就是dp[i][j]=dp[i-1][j];然后因为背包总价值最大,所以要从二者中取MAX;
- 完全背包:按最暴力的方法就是将完全背包看成无限个01背包,则
dp[i][j] = max(dp[i - 1][j],dp[i][j - w[i]]);(论述已省)
二维变一维
- 01背包:我们很容易发现dp[i]只会被i以前的状态影响,那么我们为何不逆序枚举,让dp[i]不被i之前的状态影响呢.
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100 + 10;
int w[maxn],v[maxn];
int dp[maxn];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)scanf("%d%d",&w[i],&v[i]);
for(int i = 1; i <= n; i++)
for(int j = m; j >= w[i]; j--)
dp[j] = max(dp[j],dp[j - w[i]] + v[i]);
return 0;
}
//应该很好理解
//吧?
- 完全背包:原理与01背包差不太多.只要顺序枚举即可
for(int i = 1; i <= n; i++)
for(int j = w[i]; j <= m; j++)
dp[j] = max(dp[j],dp[j - w[i]] + v[i]);
滚动数组
从前面我们就可以发现,dp[i][j]只与这一状态与上一状态有关.之前存的数据就没有用了,可以将它舍弃,所以我们可以用2M的空间存储数据,循环滚动使用,2 * m可以达到n * m同样的效果,这无疑优化了很大的空间.
//————完全
int now = 1;
for(int i = 1; i <= n; i++)
{
for(int j = w[i]; j <= m; j++)
dp[now][j] = max(dp[1 - now][j],dp[now][j - w[i]] + v[i]);
now = 1 - now;
}
//————01
int now = 1;
for(int i = 1; i <= n; i++)
{
for(int j = w[i]; j <= m; j++)
dp[now][j] = max(dp[1 - now][j],dp[1 - now][j - w[i]] + v[i]);
now = 1 - now;
}
2783

被折叠的 条评论
为什么被折叠?



