01背包问题
- 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
- 第 i 件物品的体积是 vi,价值是 wi。
- 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。
- 第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
- 接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
数据范围 0
1 2
2 4
3 4
4 5
输出样例: 8
代码
其中,初始化的部分也可以不写,因为数组定义在main函数外面,自动初始化为0了
#include
#define maxn 1010
#define max(a,b) a>b?a:b
int v[maxn],w[maxn];
//v[i],w[i]分别表示第i件物品的体积和价值。
int dp[maxn][maxn];
//dp[i][j]表示前i件物品,体积刚好为j时最大价值。
int main()
{
int n,V;
//n为物品数量,v为背包容积
scanf("%d%d",&n,&V);
for(int i=1;
i<=n;
i++)
{
scanf("%d%d",&v[i],&w[i]);
}
for(int i=0;
i<=n;
i++)
dp[i][0]=0;
//边界条件
for(int i=0;
i<=V;
i++)
dp[0][i]=0;
//边界条件
for(int i=1;
i<=n;
i++)//i表示前i件
{
for(int j=1;
j<=V;
j++) //j表示体积刚好为j
{
dp[i][j]=dp[i-1][j];
if(j>=v[i])
dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]);
}
}
int sum=0;
for(int j=1;
j<=V;
j++)
{
sum=max(dp[n][j],sum);
}
printf("%d\n",sum);
return 0;
}
对于01背包问题,需要dp[n][v]数组,即需要n*m大小的空间,如果遇到较大的数据就会被善良的出题人卡掉,那么如何进行优化呢?
#include
#define maxn 1010
#define max(a,b) a>b?a:b
int v[maxn],w[maxn];
//v[i],w[i]分别表示第i件物品的体积和价值。
int dp[maxn];
//dp[i][j]表示前i件物品,体积刚好为j时最大价值。
int main()
{
int n,V;
//n为物品数量,v为背包容积
scanf("%d%d",&n,&V);
for(int i=1;
i<=n;
i++)
{
scanf("%d%d",&v[i],&w[i]);
}
for(int i=1;
i<=n;
i++)//i表示前i件
{
for(int j=V;
j>=v[i];
j--) //j表示体积刚好为j
{
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
}
}
int sum=0;
for(int j=1;
j<=V;
j++)
{
sum=max(dp[j],sum);
}
printf("%d\n",sum);
return 0;
}
是不是很神奇,只需要把第一维全部砍掉,再把j的范围改为从后往前,j–。是什么原理呢
原理(滚动数组)
dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i])
注意到这个二维数组的下一行的值,只用到了上一行的正上方和左边的值,因此可用滚动数组的思想,只要一行即可。
【01背包及滚动数组优化(一维)】既然是要用正上方和左边的值,那么从右边开始依次求值,并覆盖在正上方的位置即可
文章图片
01背包问题题目链接
推荐阅读
- 技术|为参加2021年蓝桥杯Java软件开发大学B组细心整理常见基础知识、搜索和常用算法解析例题(持续更新...)
- 数据结构与算法|【算法】力扣第 266场周赛
- #|算法设计与分析(Java实现)—— 动态规划 (0-1 背包问题)
- 动态规划|暴力递归经典问题
- 动态规划|动态规划 —— 状压DP (附一些位运算小知识)
- 区间DP —— 能量项链
- 动态规划 —— 区间DP
- Codeforces|Codeforces Round #605 (Div. 3) D. Remove One Element
- LeetCode-28 实现strStr() KMP算法
- leetcode|递归、动态规划--Leetcode(python)