zoukankan      html  css  js  c++  java
  • 基础的背包问题解析-未更新完成

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

  • 相关阅读:
    Android(java)学习笔记98:如何让你的GridView不再滚动
    Android(java)学习笔记97:使用GridView以及重写BaseAdapter
    Android(java)学习笔记96:layout_weight使用注意事项
    Android(java)学习笔记95:Android运行时异常"Binary XML file line # : Error inflating class"
    HDU 2669 Romantic
    HDU 2674 N!Again
    二分查找
    HDU 3448 Bag Problem
    HDU 2962 Trucking
    HDU 3732 Ahui Writes Word
  • 原文地址:https://www.cnblogs.com/savennist/p/13568939.html
Copyright © 2011-2022 走看看