下面是普通版本的01背包代码!
int dp[105][1005];
for(int i=1;i<=m;i++)
for(int j=t;j>=0;j--)
{
if(j>=w[i])
{
dp[i][j]=max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]);
}else{
dp[i][j]=dp[i-1][j];
}
}
滚动数组优化二维01背包
我们可以看到dp数组需要很大,至少超过2行!
那么我们想一想可不可减少行数呢?
首先我们知道,d[i][j]的值只和它的上一种状态有关,即dp[i-1][j],也就是第i行的dp值,只与第i-1行有关,我们通过这条性质,可以将dp数组减少到两行即可,也就是滚动数组优化01背包!
如果不理解建议看下,尤其是那个表格01背包
那么如何做到呢?
很简单,我们在更新第i行数据时,之需要将原来的i-2行覆盖掉,根据i-1行,更新数据!
也就时每次i%2,如果i为奇数那么第i行数据写在第1行,i为偶数第i行数写在第0行!
最终输出的结果就是dp[m][v]
我们看下代码!
#include <iostream>
using namespace std;
int w[105],v[105];
int dp[2][1005];//滚动数组优化01背包
int main()
{
int t,m,res;
scanf("%d%d",&t,&m);
//读入数据
for(int i=1;i<=m;i++)
{
scanf("%d%d",&w[i],&v[i]);
}
for(int i=1;i<=m;i++)
{
for(int j=t;j>=0;j--)
{
if(j>=w[i])
{ //每次%2
dp[i%2][j]=max(dp[(i-1)%2][j-w[i]]+v[i],dp[(i-1)%2][j]);
}else{
dp[i%2][j]=dp[(i-1)%2][j];
}
}
}
//输出最后一个数据
printf("%d",dp[m%2][t]);
return 0;
}
一维01背包优化
最后这个优化是01背包问题空间的终极优化,原理也是十分简单,我用图例给大家讲解!
大家先明确一个概念:“时间差”
我们在第i行,从重量最重的开始遍历,也就是从后向前遍历!
这样遍历有什么好处呢?
答案就是,可以打"时间差",用一行解决问题!
上图!!!
大家仔细看图片中的注释!
还有一个小问题,我后面的元素可以借助前面的元素保证都更新,那么我前面的元素呢?
实际上,当前重量w[i]如果小于当前物品的重量时,那么它和上一行的值是相同的我们不需要更新!
大家看图!
假设i=3时,当前物品重量为4!
我们看第3行,重量从0~3都不需要更新,直接从上一行拿过来就可以了!
想必大家已经理解了,我说的时间差这个概念,下面附上代码!!
#include <iostream>
using namespace std;
int w[105],v[105];
int dp[1000];//一维优化
int main()
{
int t,m,res;
scanf("%d%d",&t,&m);
//读入数据
for(int i=1; i<=m; i++)
{
scanf("%d%d",&w[i],&v[i]);
}
for(int i=1; i<=m; i++)
for(int j=t; j>=w[i]; j--)
{
dp[j]=max(dp[j-w[i]]+v[i],dp[j]);
}
printf("%d",dp[t]);
return 0;
}
这道题是采药的题,我把链接给大家,大家可以跑一跑!
采药洛谷
谢谢观看,如果对你有帮助,多多点赞支持!