dp动态规划的三种背包问题

这篇博客介绍了动态规划在解决背包问题中的应用,包括01背包、完全背包和多重背包。01背包问题中,每种物品仅有一件,目标是使背包内物品总价值最大化;完全背包则允许无限数量的同种物品,而多重背包允许每种物品有限数量,探讨了各类问题的状态转移方程和解题思路。
摘要由CSDN通过智能技术生成

动态规划(Dynamic Programming,DP)是运筹学的一个分支,是求解决策过程最优化的过程。这里先讲一下比较常见的三种背包问题。

01背包

首先先说一下dp算法最基础的问题,01背包问题。
假设有n件物品,每件物品的重量为weight[i],价值为value[i]。现有一个容量为V的背包,问如何选取物品放入背包,使得背包内物品的总价值最大。其中
每种物品都只有一件。
这里我们用洛谷上的一道题作为例子,来描述这一类问题。
题目描述
P1048 [NOIP2005 普及组] 采药
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?
输入格式
第一行有 2 个整数 T(1≤T≤1000)和 M(1≤M≤100),用一个空格隔开,T 代表总共能够用来采药的时间,M 代表山洞里的草药的数目。

接下来的 M 行每行包括两个在 1 到 100 之间(包括 1 和 100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出格式
输出在规定的时间内可以采到的草药的最大总价值。
输入输出样例
输入
70 3
71 100
69 1
1 2
输出
3

#include <iostream> 
#include <stdio.h>
using namespace std;
int w[105],val[105];
int dp[105][1005];
int main()
{
    int t,m;
    scanf("%d %d",&t,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&w[i],&val[i]);
    }
    for(int i=1;i<=m;i++)
    {
    	dp[0][i]=0;
	}
    for(int i=1;i<=m;i++) 
        for(int j=t;j>=0;j--)  
        {
            if(j>=w[i])
            {
                dp[i][j]=max(dp[i-1][j-w[i]]+val[i],dp[i-1][j]);
            }  
            else
            {
                dp[i][j]=dp[i-1][j];
            }              
        }
    printf("%d",dp[m][t]);
    return 0;
}

这里我们解决问题的方法就是设dp二维数组,dp[i][j],其中表示的是当前记录到第几个药了,j表示的是此时还剩多长时间,那么dp[i][j]表示的就是在考虑前i个药,而且还剩下时间j的情况下,能得的最大价值。
我们这里选择的是用w数组和val数组分别存储所用的时间和每一株草药的价值,假设我们现在筛选到了第i个,且剩余的时间是可以采这珠草药的,那么此时就会有两种情况,第一种是不采,那么此时dp[i][j]=dp[i-1][j];第二种是采,那么就是dp[i][j]=dp[i-1][j-w[i]+val[i];所以只要比较这两个的大小即可,如此递推,最后推出最后的结果。
状态转移方程的模板大致可以总结为

 dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);

完全背包

关于完全背包,完全背包和01背包是类似的,不过不同点在于每个物品是无限多的,可以无限多的拿取,只要是背包的容量足够多。
模板是

dp[i][j]=max(dp[i-1][j],dp[i][j-weight[i]]+value[i];

那么这个是如何推导的呢,这里引用一下“曼切斯特的流氓”大佬的推导。

首先完全背包问题的动态转移方程可写为
(w为val[i]简写)(v=weight[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
之后就可以推出完全背包的公式了。
————————————————

这里贴上原文链接:https://blog.csdn.net/weixin_46503238/article/details/115096267

多重背包

这个问题也是01背包的变式,意思就是每个物品有有限值,但不一定只有1个,在这种情况下求最大价值。设s[i]为每种物体的最大个数。
这时候的状态转移方程为

dp[i][j] = max(dp[i-1][j-k*weight[i]]+k*value[i]),其中k<=s[i]且k*weight[i]<=j;

这里写了比较常见的三种背包问题,第一次写博客,同时也借鉴了一些大佬们的文章,希望大家多多包涵。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值