从01背包说起(上)

简介: 从01背包说起(上)

目录

引入

1.什么是动态规划?

2.什么是背包问题?

3.什么是01背包?

模板题

1.题面

2.思路

Ⅰ为何不可用贪心

Ⅱ状态转移方程

3.代码

下期预告


引入

1.什么是动态规划?

动态规划(英语:Dynamic programming,简称 DP),是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。

核心思想: 通过将问题拆分成一个一个小问题,记录过往结果,减少重复运算。

举个栗子:

A : "1+1+1+1+1+1+1+1 =?"

A : "上面等式的值是多少"

B : 计算 "8"

A : 在上面等式的左边写上 "1+" 呢?

A : "此时等式的值为多少"

B : 很快得出答案 "9"

A : "你怎么这么快就知道答案了"

A : "只要在8的基础上加1就行了"

A : "所以你不用重新计算,因为你记住了第一个等式的值为8!动态规划算法也可以说是 '记住求过的解来节省时间'"


感谢🙇‍

@四舍五入两米高的小晨

2.什么是背包问题?

背包问题(Knapsack problem)是一种组合优化的NP完全问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。相似问题经常出现在商业、组合数学,计算复杂性理论、密码学和应用数学等领域中。也可以将背包问题描述为决定性问题,即在总重量不超过W的前提下,总价值是否能达到V?它是在1978年由Merkle和Hellman提出的。

常见分类:

01背包

完全背包

多重背包

分组背包

3.什么是01背包?

01背包是背包问题中最简单的问题。01背包的约束条件是给定几种物品,每种物品有且只有一个,并且有权值和体积两个属性。在01背包问题中,因为每种物品只有一个,对于每个物品只需要考虑选与不选(0与1)两种情况。如果不选择将其放入背包中,则不需要处理。如果选择将其放入背包中,由于不清楚之前放入的物品占据了多大的空间,需要枚举将这个物品放入背包后可能占据背包空间的所有情况。

对于这类问题,可采用  深搜+剪枝 或 动态规划 的方法,今天我们用动规来AC此题。


模板题

1.题面

这类问题的模板题,有一道十分经典,它是:[NOIP2005 普及组] 采药

【NOIP2005 普及组】采药

题目描述:

       辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

       如果你是辰辰,你能完成这个任务吗?

输入格式:

第一行有 22 个整数 TT(1 \le T \le 10001≤T≤1000)和 MM(1 \le M \le 1001≤M≤100),用一个空格隔开,TT 代表总共能够用来采药的时间,MM 代表山洞里的草药的数目。

接下来的 MM 行每行包括两个在 11 到 100100 之间(包括 11 和 100100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式:

输出在规定的时间内可以采到的草药的最大总价值。

输入输出样例

输入:

70 3

71 100

69 1

1 2

输出 :

3

这道题,就是将原始题目换了个故事。原始题:

有一个容量为V的背包,还有n个物体。现在忽略物体实际几何形状,我们认为只要背包的剩余容量大于等于物体体积,那就可以装进背包里。每个物体都有两个属性,即体积w和价值v。

问:如何向背包装物体才能使背包中物体的总价值最大?

2.思路

Ⅰ为何不可用贪心

很多人看到此题第一个反应便是贪心。但为什么这个问题不能用贪心呢?

举个栗子:

我的背包容量为10,而且有4个物体,它们的体积和价值分别为

w1 = 8, v1 = 9

w2 = 3, v2 = 3

w3 = 4, v3 = 4

w4 = 3, v4 = 3

贪心是每一步采取最优拿法,即每一次都优先拿价值与体积比值最大的物体

c1 = v1/w1 = 1.125(最大)

c2 = v2/w2 = 1

c3 = v3/w3 = 1

c4 = v4/w4 = 1

所以优先拿第一个物体,随后背包再也装不下其他物体了,则最大价值为9。

但是这个问题的最优解是取物体2,3,4装进背包,最大价值为3+4+3=10!(9<10)

感谢🙇‍@Iseno_V

所以这个问题不可以用贪心法来处理。

Ⅱ状态转移方程

先设wi表示第i个物品的重量,vi表示第i个物品的价值。

动态规划的核心是状态转移方程。可以发现:最大价值是物品数量i和背包容量j的函数。

设函数f[i][j]表示前i件物品放入容量为j的背包的最大价值,

最终的最大价值就是物品数量i从0增长到n,背包容量j从0增长到m时的f[n][m]值。

前面说了,01背包对于每个物品只需要考虑选与不选(0与1)两种情况。当前容量为j,我们要考虑第i件物品能否放入?是否放入?

①如果当前背包容量j<v[i],不能放入,则f[i][j]=f[i-1][j]

②如果当前背包容量j>=v[i],能放入但是要比较代价,看放入价值高还是不放入价值高。

2.1 如果第i件物品不放入背包,则f[i][j]=f[i-1][j]

2.2 如果第i件物品放入背包,则f[i][j]=f[i-1][j-w[i]]+v[i]

如果第i件物品放入背包,则背包容量还剩j-w[i],所以要取前i-1件物品放入背包剩余容量j-w[i]所获得的最大价值f[i-1][j-w[i]]。如图:

正在上传…

重新上传

因此,得到状态转移方程:

image.gif编辑

3.代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N];//v数组存储体积,w数组存储价值
int f[N][N];
int main ()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            {
                f[i][j]=f[i-1][j];//将不能放入第i件物品的情况和能放入但是没放入的情况合并
                if(j>=v[i]) f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
            }
    cout<<f[n][m]<<endl;
    return 0;
}

image.gif


下期预告

01背包优化+ [NOIP2006 提高组] 金明的预算方案

相关文章
|
1月前
|
存储 算法
|
5月前
|
Java
01背包介绍与N皇后(dfs,考验代码能力JAVA)
01背包介绍与N皇后(dfs,考验代码能力JAVA)
从01背包说起(下)
从01背包说起(下)
48 0
|
C++
剑指Offer - 面试题47:礼物的最大价值
剑指Offer - 面试题47:礼物的最大价值
86 0
可能你已经刷了很多01背包的题,但是真的对01背包领悟透彻了吗?,看我这一篇,使君对01背包的理解更进一步【代码+图解+文字描述】
可能你已经刷了很多01背包的题,但是真的对01背包领悟透彻了吗?,看我这一篇,使君对01背包的理解更进一步【代码+图解+文字描述】
|
算法 Java 测试技术
大厂面试题:求根号2简单?高级算法你肯定不会
大厂面试题:求根号2简单?高级算法你肯定不会
238 0
大厂面试题:求根号2简单?高级算法你肯定不会
|
存储 Java
第十二届蓝桥杯省赛A组砝码称重Java解题思路及代码
第十二届蓝桥杯省赛A组砝码称重Java解题思路及代码
154 0
|
算法
01背包原理
笔记
113 0
|
Java
【蓝桥Java每日一题】——11.做菜顺序(贪心秒杀困难题)
今天给大家带来一道级别是困难的力扣题,但是利用贪心思想我们可以很快速地做出来,甚至称之为简单题也不为过,可见贪心之强大
205 0
|
机器学习/深度学习
你的背包背到现在还没烂
你的背包背到现在还没烂