题解 | #【模板】01背包#

【模板】01背包

http://www.nowcoder.com/practice/fd55637d3f24484e96dad9e992d3f62e

经典01背包问题。
解题思路比较常规。用辅助数组res存储容积为i时能装入物品的最大价值。对物品进行遍历,每次遍历中都逆序更新res,转移方程为res[j]=max(res[j-v[i]]+p[i],res[j])。最终res[v]即为要求的容积为v时所能装入物品的最大价值。
这道题设置了两问,解题上有细微差别。需要分开用两个辅助数组来存储结果。第一问求能装入物品的最大价值,没有要求刚好装满,所以直接把数组res的元素全部初始化为0即可。而第二问要求刚好装满时的最大价值。需要将res第一个元素初始化为0,代表容积为0的背包装满时最大价值为0;将其余元素全部初始化为一个很大的负数,要保证就算将所有物品的价值与这个数相加还会得到一个负数。这样,在按照与第一问同样的方法计算最大价值时,若不存在刚好装满的情况,res[v]就会为负数,因为没有办法从res[0]一直装物品装到res[v]。只有能从res[0]开始装,由于res[0]=0,才能规避掉初值的极大负值,得到一个正常的正值。所以最后判断res[0]即可,为正直接返回,为负返回0。

这里记录一下写的时候遇到的坑。
开始时将res数组初始化为大小为v的数组,提交时总有一些用例出问题。实际上这里辅助数组res[i]表示的是容积为i时能装入物品的最大价值,其范围应该是0,1,2,...,v,所以res初始化的大小应该是v+1,否则必定出错。

#include <iostream>
#include <vector>

using namespace std;

int main(){
    int n, v;
    cin >> n >> v;
    vector<int> arrv(n, 0);
    vector<int> arrp(n, 0);
    vector<int> res(v + 1, 0);
    vector<int> cres(v + 1, -99999);
    cres.at(0) = 0;
    for(int i = 0;i < n;i++){
        cin >> arrv.at(i) >> arrp.at(i);
    }
    for(int i = 0;i < n;i++){
        for(int j = v;j >= arrv.at(i);j--){
            res.at(j) = max(res.at(j - arrv.at(i)) + arrp.at(i), res.at(j));
            cres.at(j) = max(cres.at(j - arrv.at(i)) + arrp.at(i), cres.at(j));
        }
    }
    int max = res.at(v); 
    int comax = cres.at(v) > 0 ? cres.at(v) : 0;
    cout << max << endl << comax;
    return 0;
}



附一段递归代码,在第12个用例处超时,望大佬指点一下优化方法。

#include <iostream>
#include <vector>

using namespace std;

int n, V;
vector<int> price;
vector<int> volume;

int main(){
    cin >> n >> V;
    for(int i = 0;i < n;i++){
        int vt, vp;
        cin >> vt;
        cin >> vp;
        volume.push_back(vt);
        price.push_back(vp);
    }
    int put(int i, int v);
    int cput(int i, int v);
    cout << put(n - 1, V) << endl << (cput(0, V) > 0 ? cput(0, V) : 0);
}
int put(int i, int v){
    if(i < 0 || v == 0){
        return 0;
    }
    if(volume.at(i) > v){
        return put(i - 1, v);
    }
    else{
        return max(put(i - 1, v), put(i - 1, v - volume.at(i)) + price.at(i));
    }
}
int cput(int i, int v){
    if(i == n && v != 0){
        return -9999;
    }
    else if(v == 0){
        return 0;
    }
    else if(volume.at(i) > v){
        return cput(i + 1, v);
    }
    else{
        return max(cput(i + 1, v), cput(i + 1, v - volume.at(i)) + price.at(i));
    }
}

全部评论

相关推荐

不愿透露姓名的神秘牛友
07-07 13:15
点赞 评论 收藏
分享
点赞 评论 收藏
分享
06-13 17:33
门头沟学院 Java
顺序不记了,大致顺序是这样的,有的相同知识点写分开了1.基本数据类型2.基本数据类型和包装类型的区别3.==和equals区别4.ArrayList与LinkedList区别5.hashmap底层原理,put操作时会发生什么6.说出几种树型数据结构7.B树和B+树区别8.jvm加载类机制9.线程池核心参数10.创建线程池的几种方式11.callable与runnable区别12.线程池怎么回收线程13.redis三剑客14.布隆过滤器原理,不要背八股,说说真正使用时遇到了问题没有(我说没有,不知道该怎么回答了)15.堆的内存结构16.自己在写项目时有没有遇见过oom,如何处理,不要背八股,根据真实经验,我说不会17.redis死锁怎么办,watchdog机制如何发现是否锁过期18.如何避免redis红锁19.一个表性别与年龄如何加索引20.自己的项目的QPS怎么测的,有没有真正遇到大数量表21.说一说泛型22.springboot自动装配原理23.springmvc与springboot区别24.aop使用过嘛?动态代理与静态代理区别25.spring循环依赖怎么解决26.你说用过es,es如何分片,怎么存的数据,1000万条数据怎么写入库中27.你说用limit,那么在数据量大之后,如何优化28.rabbitmq如何批次发送,批量读取,答了延迟队列和线程池,都不对29.计网知不知道smtp协议,不知道写了对不对,完全听懵了30.springcloud知道嘛?只是了解反问1.做什么的?短信服务,信息量能到千万级2.对我的建议,基础不错,但是不要只背八股,多去实际开发中理解。面试官人不错,虽然没露脸,但是中间会引导我回答问题,不会的也只是说对我要求没那么高。面完问我在济宁生活有没有困难,最快什么时候到,让人事给我聊薪资了。下午人事打电话,问我27届的会不会跑路,还在想办法如何使我不跑路,不想扣我薪资等。之后我再联系吧,还挺想去的😭,我真不跑路哥😢附一张河科大幽默大专图,科大就是大专罢了
查看30道真题和解析
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-09 13:05
TMD找工作本来就烦,这东西什么素质啊😡
Beeee0927:hr是超雄了,不过也是有道理的
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务