• 动态规划
  • 01背包
    • 问题描述
    • 求解思路
  • 代码实现
  • 放入哪些物品
  • 代码

动态规划

我在上一篇博客里已经讲了一点动态规划了,传送门:算法学习 - 动态规划(DP问题)(C++)

这里说一下,遇到动态规划应该如何去想,才能找到解决办法。

最主要的其实是要找状态转移的方程,例如上一篇博客里面,找的就是当前两条生产线的第i个station的最短时间和上一时刻的时间关系。

minTime(station[1][i]) = minTime(station[1][i-1] + time[i], station[2][i-1] + time[i] + trans[i-1])

今天要讲的问题是01背包问题。

01背包

问题描述

01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2……Wn,与之相对应的价值为P1,P2……Pn。

求解这个背包能装的最大价值。(物体不能分割)。

求解思路

这个其实比上一道题难在哪里了呢?
难在上一题装配线始终是两个,不会多,不会少。我们变化的量只有装配站的多少。

这个题目变化的量一个是物品的数量,还有一个是背包的空间。就是说装配线不会随着station的多少而变化,但是背包的空间会随着物品的装入而变化。

所以我们需要做的是判断当背包剩余的空间为j的时候,能否装入第i个物品,并且总价值增加。
即:

d[j] = max ( d[j], d[j-v[i]] + w[i]); //v[i]表示第i个物品的体积,w[i]表示第i个物品的价值。

其实我最开始看到上面这个状态转移的方程的时候,觉得这不是肯定的在空间j的时候放入物品,价值大于不放入物品的。毕竟只要放入就证明增加了价值啊。

其实不是这个样子的,因为只有在最开始都没有装入的时候,所有的都是0. 装入就一定价值增加。但是假如我们的物品如下:

物品1: 空间 2 价值 5
物品2: 空间 4 价值 3

当我们放入第一件物品的时候,假设背包空间是5,那么d[2…5]都是为 5. 因为d[0…1]空间不够所以为0。 当我们放入物品2的时候,d[5] = 5 > d[5 - 4] + 3 因为d[1] = 0;

发现了没有! 并不是放入就一定总价值增加!

所以我们遍历所有物品,从第一个物品开始,找当空间为j的时候,装入物品是否会增加价值!

代码实现

代码其实行数很少,不好看那些写了两个屏幕的,可能并没有更多的功能。

//
//  main.cpp
//  DP_01backpack
//
//  Created by Alps on 15/4/28.
//  Copyright (c) 2015年 chen. All rights reserved.
//
// 代码中直接定义了石头的数量和背包的空间,其实可以不用提前定义。
// 这里为了方便,而且在C++ 11中可以动态规定数组大小。#include <iostream>
using namespace std;#ifndef STONE_NUM
#define STONE_NUM 5 //定义石头数量
#endif#ifndef BACKPACK_SPACE
#define BACKPACK_SPACE 10
#endifint main(int argc, const char * argv[]) {int stoneSpace, stoneValue;//保存当前输入的物品空间和价值int value[BACKPACK_SPACE+1] = {0}; //初始化value数组for (int i = 0; i < STONE_NUM; i++) {scanf("%d %d", &stoneSpace, &stoneValue);//接收物品输入for (int j = BACKPACK_SPACE; j > 0; j--) {//当背包空间在不同的时候,** j 一定是从大到小**if (j >= stoneSpace && value[j] < (value[j-stoneSpace] + stoneValue)) {//假如背包空间足够,并且放入总价值增加value[j] = value[j-stoneSpace] + stoneValue;//放入,并更新总价值}}}printf("%d\n", value[BACKPACK_SPACE]);return 0;
}

这里解释下,为何第二层for循环里,j 是从最大变化到最小的。因为我们比较的是当前物品放入,价值是否有变化,就是 value[j] 和 value[j - v] 比较。 假如更新了,那么 value[j + 1] 需要和 value[j + 1 - v] 比较的值,可能 value[j + 1 - v]已经被更新过了。就不行了!因为那个时候value[j + 1 -v]的总价值已经算上当前的物品了。再算就重复了。

放入哪些物品

上面的代码没有知道到底放入了哪些物品,其实是因为为了节省空间,没有保存每个 stoneSpace和 stoneValue.
所以我们把它们变成数组就好了。

然后我们首先要做的是:找到一共背包用了多少空间!

这个很重要,因为背包的最大价值不一定是装满了,所以我们要找到用了多少空间,才能知道到底放入了哪些物品。

怎么找呢?

假如我们的value数组如下:

0
0
4
6
9
10
13
15
15
19
19

很容易知道,这个背包剩余了一个空间? 为什么呢,因为最大的19有两个,j 多了1但是价值没有增加,说明这 1的空间没有放入物品,也就是空余了。

这样找到第一个最大得数的下标,就是使用的空间了。

代码

比较简单,只不过多了一步查找那些物品放入了,就是当背包空间减去物品空间,总价值也刚好增加了物品的价值数量,那么说明这个物品被放入了。

代码如下:

//
//  main.cpp
//  DP_01backpack
//
//  Created by Alps on 15/4/28.
//  Copyright (c) 2015年 chen. All rights reserved.
//
// 代码中直接定义了石头的数量和背包的空间,其实可以不用提前定义。
// 这里为了方便,而且在C++ 11中可以动态规定数组大小。#include <iostream>
using namespace std;#ifndef STONE_NUM
#define STONE_NUM 5 //定义石头数量
#endif#ifndef BACKPACK_SPACE
#define BACKPACK_SPACE 10
#endifint main(int argc, const char * argv[]) {int value[BACKPACK_SPACE+1] = {0};int stoneSpace[STONE_NUM],stoneValue[STONE_NUM];for (int i = 0; i < STONE_NUM; i++) {scanf("%d %d", &stoneSpace[i], &stoneValue[i]);for (int j = BACKPACK_SPACE; j > 0; j--) {if (j >= stoneSpace[i] && value[j] < value[j-stoneSpace[i]] + stoneValue[i]) {value[j] = value[j-stoneSpace[i]] + stoneValue[i];}}}//以上代码几乎无变化,只是存储是数组存储了。for (int i = 0; i <= BACKPACK_SPACE; i++) {printf("%d\n", value[i]);}//打印value数组,这里面存放的是,所有物品在背包只有空间i的时候,达到的最大总价值。int backPackSpace = BACKPACK_SPACE;// 得到背包空间while (value[backPackSpace] == value[backPackSpace-1]) {backPackSpace--;//假如背包价值和背包空间-1的时候价值相同,空间 -1}//找到一共使用了多少空间for (int i = STONE_NUM-1; i >= 0; i--) {if ((backPackSpace-stoneSpace[i] >= 0) && value[backPackSpace] == value[backPackSpace-stoneSpace[i]] + stoneValue[i]) { //假如减去当前物品的空间,总价值刚好和物品的价值相等,说明此物品被放入了。printf("%d ", i+1);//打印这个物品。i+1是因为物品的下标是从0开始的。backPackSpace = backPackSpace - stoneSpace[i]; //背包放入了这个物品,自然空间减少了。}}return 0;
}

整个代码比较简单。 有疑问的留言,可以相互交流。

我看了一篇其他博客,用二维矩阵入门,也觉得很棒。推荐:http://www.hawstein.com/posts/dp-knapsack.html

算法学习 - 01背包问题(动态规划C++)相关推荐

  1. vs2017\vs2019 动态规划算法实现0-1背包问题 C

    这是针对于博客vs2017安装和使用教程(详细)和vs2019安装和使用教程(详细)的动态规划算法实现0-1背包问题的示例 目录 一.问题描述

  2. 01背包问题 动态规划 java实现 简单通俗易懂

    ** 01背包问题 动态规划 ** 1.动态规划 什么是动态规划?动态规划就是将一个大问题不断向下拆分成小问题,直到拆分出的小问题可以求出其解,然后将小问题的解不断的向上合并,最终得到大问题的解决方案 ...

  3. 算法设计 - 01背包问题的状态转移方程优化,以及完全背包问题

    01背包问题的一维状态转移方程的推导 前提摘要 前面这篇博客中: 算法设计 - 01背包问题_伏城之外的博客-CSDN博客 我们已经推导出了01背包问题的二维数组dp状态转移方程公式: 假设有N种不同 ...

  4. 基于改进遗传退火算法的0-1背包问题设计与实现

    JISHOUUNIVERSITY 本科生毕业设计 题    目: 基于改进遗传退火算法的0-1背包问题设计与实现 作    者: 秦峰 学   号: 20144042001 所属学院: 信息科学与工程 ...

  5. 背包问题动态规划matlab,01背包问题动态规划详解

    计算机算法分析考试:动态规划0-1背包问题,怎么算她说她没醉,却一直摇摇晃晃掉眼泪:你说你爱她,却从未想过给她一个家. 要考试了,老师给划重点有一题:动态规划0-1背包问题,怎么算. 怎么理问题描述: ...

  6. 分支界限算法【0-1背包问题】按照优先队列式(LC)分支限界法求解0-1背包问题, 并给出限界函数,并画出该实例的状态空间树。

    目   录 回溯算法[0-1背包问题] 分支界限算法[0-1背包问题] 作业题(期末考试必考) 小结 回溯算法[0-1背包问题] 分支界限算法[0-1背包问题] 解决思路:采用优先队列式分支限界 Ø ...

  7. 01背包问题动态规划(二维数组)

    01背包问题动态规划(二维数组) 问题描述 ​ 一个旅行者有一个最多能装 M 公斤的背包,现在有 n 件物品,它们的重量分别是W1,W2,-,Wn,它们的价值分别为C1,C2,-,Cn,求旅行者能获得 ...

  8. 0-1背包问题动态规划模型的Python解法

    0-1背包问题动态规划模型的Python解法 1.01背包问题 2.Python解决方案 3.01背包问题例题 1.01背包问题 背包问题(Knapsack problem)是一种组合优化的NP完全问 ...

  9. 算法设计与分析 0-1背包问题 动态规划解法【超详细】

    0-1背包问题 问题描述 给定i个物品和一个容量为的背包,物品的重量是Wi,其价值为Vi 物品个数为i,背包容量为C. 如何选择装入背包内的物品,使得装入背包中的物品的总价值最大? 其中,每种物品只有 ...

最新文章

  1. 周志华教授:关于深度学习的一点思考!
  2. 程承熊LEE微购店的买家秀
  3. linux shell 判断一个命令是否存在
  4. 强化学习(十六) 深度确定性策略梯度(DDPG)
  5. QGLViewer 编译安装步骤
  6. 【LeetCode】剑指 Offer 27. 二叉树的镜像
  7. js中Array数组基本方法
  8. Fusion Studio 17 for Mac(视频后期特效合成软件)
  9. 一周二次课(12月12日)
  10. c语言下建立直角坐标系,大地坐标系和地心地固直角坐标ECEF转换公式和C语言函数代码...
  11. JDK源码系列 下载源码
  12. 数组公式和普通公式,差别在于思维方式的不同! 要用看数组的方式看待数据
  13. 1013. Battle Over Cities (25)
  14. 2009年最新虚拟主机提供商排名榜
  15. 阿里VIP会员看腾讯视频?这不是一个意外的选择
  16. java 保存文件在服务器_Java中如何将数据保存到服务器端
  17. t检验 显著性检验 significance test
  18. 为视图或函数指定的列名比其定义中的列多
  19. 2100306-52-1,N-Mal-N-bis(PEG4-acid)一种马来酰亚胺PEG试剂,具有两个末端羧酸和一个马来酰亚胺(Mal)基团
  20. vue-cli创建vue2或vue3新项目步骤【留底收藏】

热门文章

  1. Wireshark --> 抓包(网络分析)工具
  2. 属性选择器 class^=
  3. java 80端口_Java80端口占用异常解决方法有什么?
  4. 某联招聘版某数反反爬— 2. 总体剖析
  5. Chrome - JavaScript调试技巧总结(浏览器调试JS)
  6. java飞机大战背景图片_Java简单飞机大战(1)
  7. 安徽省宣城市住房公积金管理中心的数据安全建设实践
  8. android11有哪种手机,哪些手机可以升级安卓11 Android11支持机型有哪些
  9. Vue - 项目中使用iconfont(阿里图标库)
  10. C语言(函数指针数组)详解