人人都能学会的编程入门课
胡光
原百度高级算法研发工程师
19410 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 38 讲
开篇词 (1讲)
人人都能学会的编程入门课
15
15
1.0x
00:00/00:00
登录|注册

25 | 动态规划(下):背包问题与动态规划算法优化

你好,我是胡光,欢迎回来。
上节课呢,我们学习了动态规划算法的一般求解步骤:状态定义,推导状态转移方程、正确性证明,以及程序设计与实现。在这个过程中,我们又一次用到了之前我们讲的重要数学思维:数学归纳法 。
今天这节课,将是我们“算法数据结构篇”的最后一篇,其实从这个章节开始,我都在试图用我的语言和有序的课程设计,让你感受算法数据结构在思维层面的魅力。我还希望,你能通过这部分知识的学习,能对算法和数据结构产生兴趣,并且消除对算法学习的畏难心理。
好了,进入正题,今天我将借由动态规划算法,向你展示算法中追求极致的那一部分基因:算法优化。

初识:0/1 背包问题

想要感受算法优化,我们先从一类经典的动态规划问题,背包类问题开始。
简单的背包类问题,可以分成三类:0/1 背包问题,完全背包问题与多重背包问题。我们今天要讲的就是 0/1 背包与多重背包这两个问题。
0/1 背包问题可以说是所有背包问题的基础,它描述的场景是这样的:假设你有一个背包,载重上限是 W,你面前有 n 个物品,第 i 个物品的重量是 wi,价值是 vi,那么,在不超过背包重量上限的前提下,你能获得的最大物品价值总和是多少?
按照动态规划问题的四步走,咱们来分析一下这个问题。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

动态规划算法在解决背包问题中展现出了极致的优化能力。文章首先介绍了0/1背包问题的基本概念,通过状态定义、状态转移方程、正确性证明和程序设计与实现,深入解析了动态规划算法的求解过程。作者以数学归纳法的思路,通过程序实现展示了动态规划算法的威力。接着,文章提出了多重背包问题,指出将其转化为0/1背包问题的做法会浪费计算资源。最后,文章呼吁读者寻求更优化的解决方案。整体而言,本文通过具体问题的分析,生动地展示了动态规划算法的优化能力,对读者理解算法优化具有一定的启发意义。 文章通过介绍二进制拆分法和多重背包的拆分优化,展示了在解决背包问题中的实际应用。二进制拆分法巧妙地利用二进制数字表示法,将多重背包问题转化为0/1背包问题,从而节省了大量计算资源。通过具体案例的对比,文章生动地展示了二进制拆分法的优越性,并呼吁读者寻求更优化的解决方案。此外,文章还提出了程序设计与实现的作业题,鼓励读者通过实践来加深对算法优化的理解。 总之,本文通过具体问题的分析,生动地展示了动态规划算法的优化能力,对读者理解算法优化具有一定的启发意义。文章内容丰富,实例生动,对于对算法优化感兴趣的读者具有一定的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《人人都能学会的编程入门课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(3)

  • 最新
  • 精选
  • 栾~龟虽寿!
    听了这几次课,感觉对动态规划的理解又上了一个台阶,比如状态定义的维度分析。我们每个人都有一个装知识的小桶,桶底有小窟窿,老师正好给了我几个堵洞的石头,感谢。

    作者回复: 还是你的基础好!d(^_^o)

    2020-03-14
    2
  • 宋不肥
    作业感觉只要初始化一个w和v数组就可以呀。。。 #include<stdio.h> #define MAX_N 100 #define MAX_V 10000 int v[MAX_N + 5] = {10,20,20,7,14,7,12,12,8,16,32}, w[MAX_N + 5] = {4,8,8,3,6,3,12,12,9,18,36}; int dp[MAX_N + 5][MAX_V + 5]; int get_dp(int n, int W) { // 初始化 dp[0] 阶段 for (int i = 0; i <= W; i++) dp[0][i] = 0; // 假设 dp[i - 1] 成立,计算得到 dp[i] // 状态转移过程,i 代表物品,j 代表背包限重 for (int i = 1; i <= n; i++) { for (int j = 0; j <= W; j++) { // 不选择第 i 种物品时的最大值 dp[i][j] = dp[i - 1][j]; // 与选择第 i 种物品的最大值作比较,并更新 if (j >= w[i] && dp[i][j] < dp[i - 1][j - w[i]] + v[i]) { dp[i][j] = dp[i - 1][j - w[i]] + v[i]; } } } return dp[n][W]; } int main(){ int a; a = get_dp(5,25); printf("%d",a); }

    作者回复: 你这个初始化过程,太简单粗暴了,试想一下,如果有100种物品呢?你怎么办呢?所以,应该把你手动初始化的过程,写成程序。还记得咱们之前所讲的:把计算过程交给计算机么?

    2020-03-15
    1
  • 罗耀龙@坐忘
    茶艺师学编程 多重背包问题 最多装37元,其中是3个镀金极客币,和1个胡船长手办。 在这里体会到,要玩好数组,要留意下标,不然就只算出34。 /*多重背包*/ #include <stdio.h> #define MAX_N 100 #define MAX_V 10000 int v[12] = {0, 10, 20, 20, 7, 14, 7, 12, 12, 8, 16, 32}; int w[12] = {0, 4, 8, 8, 3, 6, 3, 12, 12, 9, 18, 36}; int dp[MAX_N + 5][MAX_V + 5]; int s[12]; int get_dp(int n, int W) { // 初始化 dp[0] 阶段 for (int i = 0; i <= W; i++) dp[0][i] = 0; // 假设 dp[i - 1] 成立,计算得到 dp[i] // 状态转移过程,i 代表物品,j 代表背包限重 for (int i = 1; i <= n; i++) { for (int j = 0; j <= W; j++) { // 不选择第 i 种物品时的最大值 dp[i][j] = dp[i - 1][j]; s[i] = {0}; // 与选择第 i 种物品的最大值作比较,并更新 if (j >= w[i] && dp[i][j] < dp[i - 1][j - w[i]] + v[i]) { dp[i][j] = dp[i - 1][j - w[i]] + v[i]; s[i] = {1}; } } } return dp[n][W]; } int main(){ printf("最多能装%d元\n", get_dp(11, 15)); puts("\n 其中的组合为:\n"); if(s[1] == 1)puts("1个镀金极客币,4kg每个,价值 10 块钱"); if(s[2] == 1)puts("2个镀金极客币,8kg每个,价值 20 块钱"); if(s[3] == 1)puts("2个镀金极客币,8kg每个,价值 20 块钱"); if(s[4] == 1)puts("1个胡船长手办,3kg每个,价值 7 块钱"); if(s[5] == 1)puts("2个胡船长手办,6kg每个,价值 14 块钱"); if(s[6] == 1)puts("1个胡船长手办,3kg每个,价值 7 块钱"); if(s[7] == 1)puts("1个西瓜,12kg每个,价值 12 块钱"); if(s[8] == 1)puts("1个西瓜,12kg每个,价值 12 块钱"); if(s[9] == 1)puts("1个哈密瓜,9kg每个,价值 8 块钱"); if(s[10] == 1)puts("2个哈密瓜,18kg每个,价值 16 块钱"); if(s[11] == 1)puts("4个哈密瓜,36kg每个,价值 32块钱"); return 0; }
    2020-10-22
收起评论
显示
设置
留言
3
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部