首页 > 其他分享 >动态规划01背包的一个例题——洛谷P2871 题解

动态规划01背包的一个例题——洛谷P2871 题解

时间:2024-09-08 22:03:54浏览次数:6  
标签:背包 洛谷 容量 题解 max 物品 例题 节点 dp

题面

有N件物品和一个容量为M的背包。第I件物品的重量是W[i],价值是D[i].
求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

样例数据

输入

4 6
1 4
2 6
3 12
2 7

输出

23

分析

(如果亲爱的读者对动态规划略有了解的话应该能看出来这是个01背包的板子题吧)暴力枚举就别想了哈,过不了的(嘻嘻)

1. 动态规划基本思想
将一个复杂问题拆成很多子问题,算出每一步的最优解,之后将每一步的合在一起

动态规划和贪心算法有点相似 下面我们通过一个简单的例题来区分一下

如下图,找出从最上面一层到最下面一层的最长路径,只能向下走(节点编号用蓝色写出,每条路的值用暗红色写出)

贪心:
从节点开始,找能走的边中最大的,重复前面的这个步骤,直到走到最下面一层,答案是10
(路线:节点1 ——> 节点3 ——> 节点5 ——> 节点9)

动态规划:

动态规划是从最后向前搜索的(这也是和贪心的最大区别)

上面这句有点个抽象 啥意思呢

就是说动态规划先从倒数第二层开始,

举个例子,

从节点4开始向下走,那要走哪条边呢?

当然是权值较大的了!

那选出来的边咋办呢?

记在节点上

就是说,给节点4赋予一个值,这个值是这个点向下所走的路的边权的总和。(因为举得节点4的例子里面节点4只能向下走一层就到头了,所以这个节点4 记的就是从节点4通往节点7的这条路的值,就是8)

以此类推,节点5的值是3,节点6的值是6

这是倒数第二层了,接下来向上搜索倒数第三层

依然是向上面说的那种方法,不同点就是要加上倒数第三层所到达的倒数第二层的节点被赋予的值

举个例子

对于节点2来说,能走的路有一条值为4的和一条值为9的,要选的是权值为9的那条

那按照上面讲述的倒数第二层的方法是不是应该让节点2的值为9呢?

并不是

节点2被赋予的值应该是 12(要选择路的权值与选择此路到达节点被赋予的值,选择和最大的)

这样一来,节点2被赋予的值就记录了从节点2走到最后一层的最大路线
(这次为什么不能选最大路线呢?因为选择了由上层向低层最大的路,并不能保证这一步被选择的节点接下来能走的路也最大)

(如下图)
以此类推,最后节点4为8,节点5为3,节点6为6,节点2为12,节点3为8,节点1为13

看到这里应该清楚01背包的思想了吧(虽然我有点啰嗦)

接下来如何码出来呢?
我们需要依靠一个东西,叫递推式

2.递推式
(先看题,看了这么久,想必大家已经把题面忘了 嘻嘻)

有N件物品和一个容量为M的背包。第I件物品的重量是W[i],价值是D[i].
求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

这道题中的递推式是

dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + d[i]);

大家一定会产生几个问题这个i是什么?这个j是什么?

先笼统解释一下:i表示物品个数,j表示容量。

这个式子可以大概翻译一下:d[i][j]等于
在0i-1个物品中选取第i个物品(大概意思就是不将第i个物品加入背包,因为0i中根本就不包括第i个物品,根本选不了)
或者在确定了0~i-1个物品的最优选法后,选取第i个物品,
以上两个方案中的最优情况。(为啥用max呢?因为题目中要求最大值)。

这个[j-w[i]]表示的是背包中剩余的空间。

如果看不懂的话,可以看这位大佬的https://zhuanlan.zhihu.com/p/345364527

我在下面复制了这位大佬的一段,希望对大家理解有帮助:

确定dp数组以及下标的含义
对于背包问题,有一种写法, 是使用二维数组,即dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
要时刻记着这个dp数组的含义,下面的一些步骤都围绕这dp数组的含义进行的,如果哪里看懵了,就来回顾一下i代表什么,j又代表什么。

确定递推公式
再回顾一下dp[i][j]的含义:从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。

那么可以有两个方向推出来dp[i][j],

由dp[i - 1][j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]
由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么dp[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值
所以递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

废了好大劲,but还没完,因为如果写这样的二维数组会崩空间(想不到吧 嘻嘻)

3.优化成省空间的一维数组

回顾前面的递推式

dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + d[i]);

我们发现,如果把dp[i-1]层的变成d[i]层的,好像也是可以的哦?

那么,这个式子就变成了dp[i][j]=max(dp[i][j],dp[i][j-w[i]]+d[i]);

那这看上去都是dp[i]层的,那这个i是不是就没用了呢?对,就是没用了

于是可得

dp[j]=max(dp[j],dp[j-w[i]]+d[i]);

大功告成,上代码(我在这里用的字母是a,个人习惯,把字母dp全换成a就好了)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
int w[5000],d[5000],a[50000];
int main()
{
	cin>>n>>m;
	
	for(int i=1;i<=n;i++)
	{
		cin>>w[i]>>d[i];
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=m;j>=w[i];j--)
		{
			a[j]=max(a[j-w[i]]+d[i],a[j]);
		}
	}
	cout<<a[m];
	return 0;
}

膜拜大佬https://zhuanlan.zhihu.com/p/345364527写得太好了,太清楚了,看懂了。

最后祝大家学习快乐(嘻嘻)

标签:背包,洛谷,容量,题解,max,物品,例题,节点,dp
From: https://www.cnblogs.com/a-good-cat-001/p/18403347

相关文章

  • BZOJ 3796 Mushroom追妹纸 题解
    Statement给\(s_1,s_2,s_3\),求最长的\(w\)的长度,满足\(w\)是\(s_1\)子串\(w\)是\(s_2\)子串\(s_3\)不是\(w\)子串Solution1以下是我没看题解瞎胡的首先一个弱智想法是,枚举\(s_1\)上\(w\)的左端点,二分右端点,判定时\(s_2\)用SAM,\(s_3\)用单串AC自动......
  • BZOJ 4502 串 题解
    妙妙数数题key:数数题通常是,对于特定形式的计数,就盯着这个模式观察,看出一些充要条件、计数形式的转化,然后想办法维护。优化的本质就是把难算的变成好算的,把不好一起统计的(只能一个个数的)以某种角度、用某些数据结构,一起统计(多个多个数)。我觉得难点通常在于“盯出一些充要条件”,......
  • 题解:AT_arc116_b [ARC116B] Products of Min-Max
    在题库里面乱翻,就翻到了。因为在这道题里面子序列不需要考虑元素顺序,所以原序列无论是什么顺序都不会影响答案。所以先把元素按照从大到小的顺序排列,然后考虑每个元素的贡献。在当前序列中,对于元素\(a_i\),不妨设其为最小值,并去寻找它能作为哪些序列的最小值。容易发现它作为最......
  • 题解:AT_abc369_c [ABC369C] Count Arithmetic Subarrays
    很水的一道题,但是硬控我半个小时呜呜呜。它问等差数列的数量,我们发现只要找到所有的等差数列,那么答案一定包含在这些数列的连续子序列中。求所有等差数列显然可以线性,我们求出每个等差数列的长度\(n\),那么连续子序列个数即为\(n(n+1)\over2\)。至于求的话我定义了两个指针,每......
  • AtCoder Beginner Contest 253 A~E 题解
    A-Median?题目大意给定正整数\(a,b,c\),判断\(b\)是否为三个数中的中位数(即从小到大排序后是第二个,不是平均数)。\(1\lea,b,c\le100\)输入格式\(a~b~c\)输出格式如果\(b\)是三个数中的中位数,输出Yes;否则,输出No。样例\(a\)\(b\)\(c\)输出\(5\)\(3\)\(2\)Y......
  • AtCoder Beginner Contest 241 (Sponsored by Panasonic) D~F 题解
    D-SequenceQuery题目大意我们有一个空序列\(A\)。请依次处理\(Q\)个命令,每个命令有三种类型,每种类型的格式如下:1x:将\(x\)加入\(A\)(不去重)2xk:求在\(A\)的\(\lex\)的元素中,第\(k\)大的值。3xk:求在\(A\)的\(\gex\)的元素中,第\(k\)小的值。\(1\leQ\le2\times10^5......
  • AtCoder Beginner Contest 242 C~E 题解
    C-1111galpassword题目大意给定正整数\(N\),求符合下列条件的整数\(X\)的个数,对\(998244353\)取模:\(X\)是\(N\)位的正整数\(X\)的每一位数都在\([1,9]\)之间(0不行);\(X\)的相邻两位数之差的绝对值不超过\(1\)。\(2\leN\le10^6\)输入格式\(N\)输出格式输出答案。样......
  • AtCoder Beginner Contest 245 A~E 题解
    A-Goodmorning题目大意在同一天里,Takahashi在\(A\)时\(B\)分起床,Aoki在\(C\)时\(D\)分\(1\)秒起床,请问谁起床更早?\(0\leA,C<24\)\(0\leB,D<60\)输入格式\(A~B~C~D\)输出格式输出起得更早的人的名字(Takahashi或Aoki)。样例\(A\)\(B\)\(C\)\(D\)输出\(7\)......
  • AtCoder Beginner Contest 244 D~F 题解
    D-SwapHats题目大意有\(3\)个Takahashi,他们帽子的颜色分别为\(S_1,S_2,S_3\)。我们现在想通过正好\(10^{18}\)次操作,使得\(S_i=T_i\)。每次操作如下:选择\((i,j)\),交换\(S_i\)和\(S_j\)。试问能否达成目标?输入格式\(S_1~S_2~S_3\)\(T_1~T_2~T_3\)输出格式如果能达......
  • ARC138 B - 01 Generation 题解
    ARC138B-01Generation思路考虑逆向思维,很容易想到可以优先从后面删掉0(操作B的逆向操作),然后如果前面是0则删掉它并将序列翻转(操作A的逆向操作),一直重复这两个步骤直到字符串为空。如果中途无法操作,输出No,否则输出Yes。下面我们来证明这个方法的正确性:首先,假设有一个序列\(A......