基础的背包问题解析-未更新完成

例题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

原文地址:https://www.cnblogs.com/savennist/p/13568939.html