• AcWing 3. 完全背包问题 学习笔记


    有 N� 种物品和一个容量是 V� 的背包,每种物品都有无限件可用。

    第 i� 种物品的体积是 vi��,价值是 wi��。

    求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
    输出最大价值。

    输入格式

    第一行两个整数,N,V�,�,用空格隔开,分别表示物品种数和背包容积。

    接下来有 N� 行,每行两个整数 vi,wi��,��,用空格隔开,分别表示第 i� 种物品的体积和价值。

    输出格式

    输出一个整数,表示最大价值。

    数据范围

    0 0

    输入样例
    1. 4 5
    2. 1 2
    3. 2 4
    4. 3 4
    5. 4 5
    输出样例:
    10
    
    难度:简单
    时/空限制:1s / 64MB
    总通过数:140737
    总尝试数:253360
    来源:背包九讲 , 模板题
    算法标签

    挑战模式

    1. #include
    2. using namespace std;
    3. const int N=1010;
    4. int v[N],w[N];
    5. int f[N];
    6. int main()
    7. {
    8. int n,m;
    9. scanf("%d%d",&n,&m);
    10. for(int i=1;i<=n;i++) scanf("%d%d",&v[i],&w[i]);
    11. for(int i=1;i<=n;i++)
    12. for(int j=v[i];j<=m;j++)
    13. f[j]=max(f[j],f[j-v[i]]+w[i]);
    14. printf("%d\n",f[m]);
    15. return 0;
    16. }

    完全背包问题是这样的:给定一个容量为m的背包,可以选择的物品有n件,每一件物品的体积是vi,每一件物品的价值是wi,我们要让背包所装的物品的总价值最大, 求这个最大的价值是多少

    这个问题的独特之处在于,不超过背包容量的情况下,某一件特定的商品可以选择无数次。

    公式可以经过数学推导出来,看起来非常简单的代码,其实要经过挺长的推导

    1. for(int i=0;i
    2. for(int j=v[i];j<=m;j++)
    3. f[j]=max(f[j],f[j-v[i]]+w[i]);

    数学推导如下:

    我们有n件物品,对于某一件物品i进行考虑,在不超过背包容量j的情况下,物品i可以选择0件,1件,2件……k件……f[i][j]表示的是选择i件物品,背包容量为j的情况下能装的最大的价值。所以还是让i从1开始计数方便描述一些,下面贴一份代码

    1. #include
    2. using namespace std;
    3. const int N=1010;
    4. int v[N],w[N];
    5. int f[N][N];
    6. int main()
    7. {
    8. int n,m;
    9. scanf("%d%d",&n,&m);
    10. for(int i=1;i<=n;i++) scanf("%d%d",&v[i],&w[i]);
    11. for(int i=1;i<=n;i++)
    12. {
    13. for(int j=1;j<=m;j++)
    14. {
    15. f[i][j]=f[i-1][j];
    16. if(j>=v[i]) f[i][j]=max(f[i-1][j],f[i][j-v[i]]+w[i]);
    17. }
    18. }
    19. printf("%d\n",f[n][m]);
    20. return 0;
    21. }

    f[i][j]=f[i-1][j];

    这一行表示的是,不选第i件物品,那么最大值就是f[i-1][j],我们不需要考虑这个数字的具体数值是多少,属于是一种递推的思路

     

    if(j>=v[i]) f[i][j]=max(f[i-1][j],f[i][j-v[i]]+w[i]);

    如果背包足够放下第i件物品,好像改成这样也可以过

     

    if(j>=v[i]) f[i][j]=max(f[i-1][j],f[i][j-v[i]]+w[i]);

     

    接下来考虑的问题是,能不能把二维的答案数组优化为一维的答案数组,发现把循环范围改成从v[i]开始,可以直接把第一维去除,代码的含义没有发生改变,(这里其实不太懂,f[i][j-v[i]]和f[i-1][j]为啥一样可以直接去掉第一维呢) 

     

     

  • 相关阅读:
    消息队列-概述-JMS和AMQP
    webpack:使用externals配置来排除打包后的某个依赖&插件IgnorePlugin的使用
    面试题--从键盘输入网站到网页显示,之间发生了什么
    《UNIX网络编程》第一步:编写自己的daytime客户端,并从daytime服务器获取时间
    1.3 常规信息系统集成技术
    fiddler导出录制脚本并导出jmter脚本文件
    B. M-arrays
    快速幂求逆元
    给sample_gpt 增加 lisa 微调
    Linux学习——文件IO
  • 原文地址:https://blog.csdn.net/L3102250566/article/details/134490467