完全背包问题(详细解答)

完全背包问题(详细解答)首先完全背包问题需要01背包问题做铺垫,如果读者01背包问题没有解决,一定要理解之后,在看完全背包问题,包括01背包的优化!这里是01背包这里是01背包的全部优化好,我们开始完全背包!完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是v[i],价值是val[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。从定义中可以看出,与01背包的区别01背包最多只能拿一件物品,完全背包则不然,只要空间够多,一种物品我可以拿n件!01

大家好,又见面了,我是你们的朋友全栈君。

首先完全背包问题需要01背包问题做铺垫,如果读者01背包问题没有解决,一定要理解之后,在看完全背包问题,包括01背包的优化!
这里是01背包
这里是01背包的全部优化

好,我们开始完全背包!

完全背包定义

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是v[i],价值是val[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

从定义中可以看出,与01背包的区别01背包最多只能拿一件物品,完全背包则不然,只要空间够多,一种物品我可以拿n件!

01背包的状态转移方程为:dp(i,j)=max(dp(i-1,j),dp(i-1,j-v[i])+val[i])
完全背包的状态转移方程:dp(i,j)=max(dp(i-1,j),dp(i,j-v)+val[i])

我们可以看出,完全背包的动态转移方程max中第二项为i,而不是i-1。

为什么呢?

我们用01背包的思想去推导,完全背包的动态转移方程

完全背包状态转移方程推导

首先完全背包问题的动态转移方程可写为
(w为val[i]简写)(v=v[i]简写)

dp(i,j)=max(dp(i-1,j) , dp(i-1,j-v)+w , dp(i-1,j-2v)+2w , dp(i-1,j-3v)+3w,
~~(以此类推到k) ,dp(i-1,j-k*v+kw))

我简单解释一下上面的方程,其实就是利用01背包思想,要求无限个物品,实际上我最多能装V/v[i]个 (总体积除以的单个个体积),所以我从装0个,到装一个,2个,3个,k个这里面一定有其中一个,是能产生最大的价值!

然后我们利用上述公式推导出”完全背包的状态转移方程”

开始推导
(时刻注意与这个方程的联系)

dp(i,j)=max(dp(i-1,j) , dp(i-1,j-v)+w , dp(i-1,j-2v)+2w , dp(i-1,j-3v)+3w,
~~(以此类推到k) ,dp(i-1,j-k*v+kw))

推导开始

还是利用01背包思想
dp(i,j-v)=max( dp(i-1,j-v) , dp(i-1,j-2v)+w,dp(i-1,j-3v)+2w , dp(i-1,j-4v)+3w,~~
~依次类推到k , dp(i-1,j-kv)+(k-1)w) )

我们在这个方程两侧同时加上w,即可得到

dp(i,j-v)+w=max( dp(i-1,j-v)+w , dp(i-1,j-2v)+2w,dp(i-1,j-3v)+3w , dp(i-1,j-4v)+4w,~~dp(i-1,j-kv)+kw)

我们在回顾一下这个方程

dp(i,j)=max(dp(i-1,j) , dp(i-1,j-v)+w , dp(i-1,j-2v)+2w , dp(i-1,j-3v)+3w,
~~(以此类推到k) dp(i-1,j-k*v)+kw))

可以发现dp(i,j-v)+w可以替代

dp(i-1,j-v)+w , dp(i-1,j-2v)+2w , dp(i-1,j-3v)+3w,~~, dp(i-1,j-k*v)+kw

所以我们得出
完全背包的状态转移方程:dp(i,j)=max(dp(i-1,j),dp(i,j-v)+w)

好了我们推导完成。
然后我们看下代码:

#include <iostream>
using namespace std;

int N,V;
int v[1010],val[1010];
int dp[1010][1010];
int main()
{ 
   
    scanf("%d%d",&N,&V);
    for(int i=1; i<=N; i++)
    { 
   
        scanf("%d%d",&v[i],&val[i]);
    }
    for(int i=1; i<=N; i++)
        for(int j=0; j<=V; j++)
        { 
   
            dp[i][j]=dp[i-1][j];//继承上一个背包
            if(j>=v[i])
            { 
     //完全背包状态转移方程
                dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+val[i]);
            }
        }
    printf("%d",dp[N][V]);
    return 0;
}

从宏观上理解,为什么会这样呢?
在这里插入图片描述

我从代码的角度阐释一下这个问题!
注意我们现在并没有对dp数组进行降维!
我们的j是从0开始的,依次递增这个是完全背包的关键,也是与01背包本质的区别
dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+val[i]);
首先要满足完全背包的动态转移方程,就要先知道dp(i,j-v)的大小
正好我们是从0开始的,并不是从后往前,也就是当求到dp(i,j)时
dp(i,j-v),在前面已经求过!!!
所以我们可以应当理顺的求出dp(i,j)而不再是向01背包要考虑前i-1时候的状态!

完全背包的优化

然后我们根据01背包的优化原则对,完全背包进行优化!
优化后的动态方程
dp[j]=max(dp[j],dp[j-v]+w)

代码(里面有一个点需要理解,我写在注释里了)

#include <iostream>
using namespace std;

int N,V;
int v[1010],val[1010];
int dp[1010];
int main()
{ 
   
    scanf("%d%d",&N,&V);
    for(int i=1; i<=N; i++)
    { 
   
        scanf("%d%d",&v[i],&val[i]);
    }
    for(int i=1; i<=N; i++)
        for(int j=0; j<=V; j++)
        { 
   
            dp[j]=dp[j];//此时右边的dp[j]是上一层i-1的dp[j],然后赋值给了当前i的dp[i]
            if(j>=v[i])
            { 
   
                dp[j]=max(dp[j],dp[j-v[i]]+val[i]);//dp[j-v[i]],已经被算过
            }           
        }
    printf("%d",dp[V]);//输出最大体积,即最优解

    return 0;
}

感谢观看,希望大家多多支持一键三连!!
嘻嘻~~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/147830.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 基于speech模块的久坐提醒小程序「建议收藏」

    基于speech模块的久坐提醒小程序「建议收藏」每天在电脑前坐很长的时间,因为有时候太过投入一下子就过去了若干个小时,容易猝死。于是心血来潮的想要写一个防久坐提醒小程序:第一种模式(最简单模式),若输入伏案工作时间数值不对则产生一个错误并退出。代码如下:importspeechimporttimeclassDebug:def__init__(self):self.start_time=time.time()self.minutes=int(input(“How

    2022年9月30日
    2
  • 数学之美 系列二 — 谈谈中文分词

    数学之美 系列二 — 谈谈中文分词

    2021年8月1日
    76
  • TLD(Tracking-Learning-Detection)一种目标跟踪算法

    TLD(Tracking-Learning-Detection)一种目标跟踪算法原文:http://blog.csdn.net/mysniper11/article/details/8726649视频介绍网址:http://www.cvchina.info/2011/04/05

    2022年8月5日
    8
  • PhantomJS快速入门「建议收藏」

    PhantomJS快速入门「建议收藏」PhantomJS快速入门  本文简要介绍了PhantomJS的相关基础知识点,主要包括PhantomJS的介绍、下载与安装、HelloWorld程序、核心模块介绍等。由于鄙人才疏学浅,难免有疏漏之处,欢迎指正交流。  1、PhantomJS是什么?  PhantomJS是一个基于webkit的JavaScriptAPI。它使用QtWebKit作为它核心浏览器的功能,使用webkit…

    2022年7月26日
    16
  • 前端面试题:闭包_前端设计模式面试题

    前端面试题:闭包_前端设计模式面试题前段时间一直在投一些中小型公司吧,感觉好久都收不到反馈,也不知道是被淘汰了还是没出结果呢,最近开始投一些大一点的公司准备尝试一下,就在昨天接到面试电话的时候,接受到了滴滴的毒打。跟一些面试不一样的是不只是一些基础的基本概念吧,比如说什么是原型和原型链,说一下继承,讲一下this指向之类的。更多的是为什么要这样用,手写算法,预测输出结果之类的面试题。印象最深刻的应该就是那道关于闭包的题目了吧,是预测一个程序的输出结果,当时看的我是晕头转向,大厂的面试也是招架不住,真的是把我给面到自闭,感觉自己啥也不是,估

    2022年8月29日
    6
  • HTML5:移动端开发入门[通俗易懂]

    HTML5:移动端开发入门[通俗易懂]HTML5:移动端开发入门一、前言常见的移动端开发分为移动版网站和响应式设计。移动端开发可以让技术人员专注于移动端的页面优化,而无需在意桌面版的兼容,但页面一旦改动内容,维护成本就翻倍了;响应式设计让开发人员只需维护一份项目,节省开发和维护成本,不过缺点是需要做好移动端和桌面端的兼容,也十分考验页面设计。两种开发方式孰强孰弱,暂无定论,本博客主要探讨一下移动端开发的技巧。二、移动端开发技巧1.Viewport设置传统桌面端网站的显示窗口往往都是在1024X768的分

    2022年6月21日
    30

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号