基础的背包问题解析-未更新完成
例题POJ-3624
众所周知,
b站是个学习的地方
先上一波基础视频讲解
根据上述视频里的基本思想,
我写出了一个酱紫的二维数组代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 3500;
int n,w;
int size[maxn],value[maxn];
int dp[maxn][15000];//dp[编号][容量]
int main()
{
freopen("in.txt","r",stdin);
memset(dp,0,sizeof(dp));
cin>>n>>w;
for(int i=1;i<=n;i++)
{
cin>>size[i]>>value[i];
}
for(int i=1;i<=n;i++)//编号
{
for(int k=1;k<=w;k++)//容量
{
//需不需要放入第k个物体
if(k-size[i]>=0) dp[i][k] = max(value[i]+dp[i-1][k-size[i]],dp[i-1][k]);
else dp[i][k] = dp[i-1][k];
}
}
for(int i=0;i<=n;i++)
{
for(int k=0;k<=w;k++)
{
printf("%3d",dp[i][k]);
}
cout<<endl;
}
cout<<dp[n][w]<<endl;
return 0;
}
然后顺利地MLE了~
上面这种解法虽然没错,
但是由于数组太大,
内存真的会超限
下面介绍优化方案
换一个思路,
假设我们现在有一个容量-价值的一位数组bag
bag[i]指i容量目前所能够存储的最大的价值
我们需要做到的,就是更新这个bag数组
那么,如何更新?
假设bag初始值为0,
我们依次遍历每一个物品i:
对于每一个物品i,我们依次检查可装入的bag中的位置k(即size[i] <= k <= w):
如果 bag[k-size[i]] + value[i] > bag[k]
则更新 bag[k] = bag[k-size[i]] + value[i]
那么,对于需要进行更新的内循环而言,k的遍历应当递增还是递减?
尽管网络上有代码按照k递减的方式进行了遍历,
但是我依然想试一试递增
原因是
我认为bag[k]中低k(容量)的更新可能会影响高容量的更新,也许这样后更新的高容量可能会在更新后保持最优状态
那么,暂且试一试吧~
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 3500;
int n,w;
int size[maxn],value[maxn];
int bag[15000];//dp[编号][容量]
int main()
{
freopen("in.txt","r",stdin);
memset(bag,0,sizeof(bag));
cin>>n>>w;
for(int i=1;i<=n;i++)
{
cin>>size[i]>>value[i];
}
for(int i=1;i<=n;i++)//编号
{
//for(int k=size[i];k<=w;k++)//容量递增遍历
for(int k=w;k>=size[i];k--)//容量递减遍历
{
bag[k] = max(bag[k-size[i]] + value[i],bag[k]);
}
//经过实验发现,容量遍历应当按照递减的顺序
//这是为什么呢???
}
cout<<bag[w]<<endl;
return 0;
}
带入数据进行操作后,发现递增遍历是错误的
看来递增遍历真的不行,必须使用递减遍历
把代码交到POJ得到结果
用户 | 问题编号 | 结果 | 内存 | 时间 | 语言 | 代码长度 |
---|---|---|---|---|---|---|
Savenneer | 3624 | Accepted | 788K | 360MS | G++ | 655B |
那么为什么呢?
正在探索中···
in.txt中的测试样例是:
4 6
1 4
2 6
3 12
2 7
对应的答案是:23
OK