C语言(CED)01背包——动态规划第二题

一、问题描述

给定n种物品和一个背包。物品i的质量Wi,其价值Vi,背包的容量为c。问如何选择装入背包中的物品,使得装入背包中的物品总价值最大?

二、解题思想

        01背包和最长公共子序列都是动态规划题目中求最优解的问题,不同在于,01背包问题,即使发现物品可以放入背包,但是在采取放或者不放的措施时,还要进行选择。(这就是保证最优解的条件)

        我们先根据题意有如下假设:假设物品的种类和背包的容量是变化的,是逐渐增多的。我们每个不同容量的背包的最大价值,建立在先前背包最大价值的基础上。例如:背包容量为5的最优解,建立在背包容量为4的最优解的基础上。

        既然容量和物品种类是变化的,那么我们建立一个二维数组(下文均称最佳价值表),横向代表背包容量,纵向代表物品种类,将每个不同容量的背包的最优解记录在最佳价值表里(这个最佳价值表记录的是满足题意的不同背包容量的最优解),如下图所示。由此正式开始思解题算法:思考递推式。

       依照假设,就会得出如下情况:

A、当只有0种物品时,无论背包的容量是多少,背包内物品的总价值都为0(因为没有东西可放);当物品的种类很多时,但是背包的容量为0,背包内物品的总价值仍然为0(因为放不进去啊!)所以这个最佳价值表的第0行,第0列都是“0”,其中V[0][0]=0,不是因为我在程序中按照上述赋值为0,其真实原因是:只要是宏变量,声明在头文件下的变量,其初值都会自动为0。上述内容相当于对这个最佳价值表做了一个初始化,如下图所示:

B、当物品的种类和背包容量按照上图递增时,就会又出现一种情况:物品不能放入背包(因为物品的质量大于当前背包可容纳的质量)、物品能放入背包。

C、物品能放入背包也要分两种:物品要放入、物品不放入。那么可能你要提问了,为什么物品能装入但是却不选择装入呢?

因为我们这个二维数组存储的是背包的最佳价值表。这个物品虽然能放到背包内,但是如果它的体积过大,放入后势必会影响后续的物品放入,导致此最佳价值表违反了其“最佳”二字。如果第?个物品没有装入背包,则背包中物品价值就等于把前?−1个物品装入容量为?的背包中所取得的价值; 如果把第?个物品装入背包,则背包物品的价值等于第?−1个物品装入容量为?−weight[?]的背包中的价值加上第?个物品的价值value[?]。

综上:

A、V[i][0]=V[0][j]=0       //简单初始化

B、V[i][j]=V[i-1][j]          //物品不能放入

C、V[i][j]=max(v[i-1][j-weight[i]]+value[i],v[i-1][j])   //物品能放入

表达式详细解析:

看到这,有的读者就会有很多问题,我来以一问一答的形式让大家更加来了解这道题目的解题思想:

Q1:为什么表达式中每次用当前背包的总容量和新出现的物品的质量作比较,而不是用背包剩余的容量与新出现的物品的质量作比较?

A1:这个问题也是我接触动态规划问题之初提过的一个问题。01背包是典型的动态规划问题,既然是动态规划问题,那么就要动起来,整个问题中,动就只有一个——物品放入背包中。你可以设想一下,假设你在实际操作的时候,虽然给出的物品很多,但因为你目光有限,所以看到的东西也是一个一个进入眼帘。你可能会先将一个物品放入背包,但是因为后来出现了又小、价值又高的物品,你在权衡之后,可能又得把之前放入的这个物品掏出,腾出空间来放当前这个质量小、价值高的物品·······说了这么多铺垫,可能有的人已经明白了:这道题的关注点只在于背包能放得下还是放不下,而不是背包放进一些东西之后剩余的空间放的下还是放不下。这个其实直接可以从上述C的表达式可以看出,即:发现物品可放入的时候,你需要以背包的总价值作为衡量依据,到底是放入价值更高了(此时有的人可能会问了,难道物品放入背包后价值还会降低?因为放入物品的时候,需要腾出一定的空间,这就需要拿出背包里的物品,所以放入物品价值不一定更高)还是不放价值更高了,所以用一个max函数来比较。如果发现放入价值高,那就得腾出空间(用最佳价值表的纵轴坐标)

Q2:做这类问题的时候,有什么秘诀没有?

A2:1、既然是动态问题,那么我们的大脑就得灵活,而且得联系实际情况,把大问题化成简单的小问题。计算机是一个很傻的处理机器,重复做着相同的工作,唯一的优点就是快,我们需要做的事情就是告诉他应该做什么事情,做的次数等,其他的就不需要多想了。 2、第二点就是不要多想,直接推导递推式,然后求解,就像Q1的那种问题就不要多加考虑了。

三、具体实现

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
int V[100][100];//用来存储背包的最大价值
int weight[100]; //存储物品的重量
int value[100];//存储物品的价值
int state[100];//存储物品的选取状态
int max(int a,int b)//比较价值大小函数
{if (a>=b)return a;else return b;
}
int KnapSack(int n,int weight[],int value[],int state[],int capacity)//动态规划求解函数
{int i,j;//循环变量//V[0][0] = 0;for (i=1;i<=n;i++)//当j=0时(j代表背包容量),0容量什么都装不进去,所以V[i][j]=0;V[i][0]=0;for (j=1;j<=capacity;j++)//当i=0时,代表没有物品,即使背包容量再大,其V[0][j]=0;V[0][j]=0;//#####下面进行判断######for (i=1;i<=n;i++)//i代表物品,j代表背包容量{//j代表背包的容量,将其从0逐步增加到输入的背包容量,相当于以背包的容量为限制,一步一步求得最大价值的方法。for (j=1;j<=capacity;j++){if(j<weight[i])//表示该物品?不能装入背包。V[i][j]=V[i-1][j];//表明此处的价值等于前i-1个物品装入的价值。else//第?个物品的重量小于背包的容量后就会有两种情况,一种放入,一种不放入,求这两种情况中Value最大的。V[i][j]=max(V[i-1][j],V[i-1][j-weight[i]]+value[i]);//如果把第?个物品装入背包,则背包物品的价值等于第?−1个物品装入容量位?−weight[?]的背包中的价值加上第?个物品的价值value[?]//如果第?个物品没有装入背包,则背包中物品价值就等于把前?−1个物品装入容量为?的背包中所取得的价值。}}j=capacity;//为标记“哪件物品放入背包”做准备for(i=n;i>=1;i--)//标记选出的物品函数{if(V[i][j]>V[i-1][j]){state[i]=1;//1表示选中j=j-weight[i];}elsestate[i]=0;//0表示未选中}printf("选中的物品是:");for(i=1;i<=n;i++)printf("%d ",state[i]);printf("\n");cout<<"V[i][j]中的数字是:\n";for(int i=0;i<=n;i++){for(int j=0; j<=capacity;j++){printf("%3d", V[i][j]);if (j == capacity){printf("\n");}}}return V[n][capacity];
}
int main()
{int s;//获得的最大价值int n = 0;//用于循环输入cout<< "请输入物品的个数:";cin >> n;cout << "请输入物品对应的质量:";for (int i = 1; i <= n; i++)cin >> weight[i];cout << "请输入物品对应的价值:";for (int i = 1; i <=n; i++)cin >> value[i];cout << "请输入背包最大容量:";int capacity;cin >> capacity;//背包最大容量s = KnapSack(n, weight, value, state, capacity);cout<<"最大物品价值为:"<<s<<endl;system("pause");return 0;
}

其中有一个for循环用来找出哪些东西被放入背包中,1代表放入,0代表没放入。 

为了方便理解,我来多贴几张图,在这里就不做gif图了,大家顺着我的这个图去理解。

函数种前两个for循环程序执行之后:(蓝色区域为最佳价值表区域)

这个是只有物品1的时候: 

出现物品2:其中绿色的6就是一个在比较之后填入的价值,绿色的9是当前两个物品的总和。

按照函数中的算法,一个一个模拟的把数字填写进去,相信你就会理解这道题目了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/531097.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言(CED)gameboy接馅饼问题

一、题目大意 都说天上不会掉馅饼&#xff0c;但有一天gameboy正走在回家的小径上&#xff0c;忽然天上掉下大把大把的馅饼。这馅饼别处都不掉&#xff0c;就掉落在他身旁的10米范围内。馅饼如果掉在了地上当然就不能吃了&#xff0c;所以gameboy马上卸下身上的背包去接。但由…

C语言(CED)递归实现汉诺塔问题

一、问题大意 大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定&#xff0c;任何时候&#xff0c;在小圆盘上都不能放大圆盘&#xff0c;…

C语言(CED)智力大冲浪——贪心算法第一题

一、题目大意 小伟报名参加中央电视台的智力大冲浪节目&#xff0c;本次挑战赛吸引了众多参赛者&#xff0c;主持人为了表彰大家的勇气&#xff0c;先奖励每个参赛者m元。先不要太高兴&#xff01;因为这些钱还不一定都是你的&#xff01;接下来主持人宣布了比赛规则&#xff…

C语言(CED)钢条最优切割收益

目录 一、题目大意 二、大致思路 三、具体实现 一、题目大意 一家公司购买长钢条&#xff0c;将其切割成短钢条出售&#xff0c;切割本身没有成本&#xff0c;长度为i的短钢条的价格为Pi。那给定一段长度为n的钢条和一个价格表Pi,求钢条的切割方案使得收益Rn最大。提示&…

撰写paper时,如何在word里输入图片或其他文献(PDF)里的公式?(更新时间2022.03.01)

我们在写paper时&#xff0c;经常会遇到在Word里编写数学公式的问题&#xff0c;其中大多数公式是已经存在的&#xff0c;所以只需要识别、复制、粘贴即可&#xff0c;那么接下来&#xff0c;我就介绍一下“Mathtype”“Mathpix”的方法&#xff0c;分为所需软件、软件操作、公…

家里接入某运营商300M宽带,为何网速还是很慢?(还未装修房屋的请进来)

&#xff08;请先看置顶博文&#xff09;本博打开方式&#xff0c;请详读_liO_Oil的博客-CSDN博客_怎么把androidstudio卸载干净 引言&#xff1a;家里接入300M的宽带&#xff0c;但是自我感觉网速不佳&#xff0c;遂结合所学知识&#xff0c;对此问题进行分析、研究和调察&…

(CED)列指针与行指针的联系与区别

一、列指针&#xff08;竖为列&#xff09; 1、列指针相关定义 列指针&#xff1a;被称为是指针变量指向二维数组的某个元素 一般使用时会有如下定义&#xff1a; int a[3][4]{1,2,3,4,5,6,7,8,9,10,11,12}; int *p;而上述代码定义的指针p&#xff0c;一般按照下表方式指向…

一、Pytho第一课——Python安装及配置路径方法(最详细小白教程,没有之一。如若不懂,不是还可以私信嘛!对吧?)

目录 一、下载软件 二、安装 三、编辑器 四、在Pycharm上成功运行Python程序&#xff08;配置Python解释器&#xff09; 一、下载软件 官方下载地址&#xff1a;https://www.python.org/downloads/&#xff08;打开似乎很吃力&#xff0c;必要时刻“挂灯”&#xff09; …

二、Python第二课——变量命名规则及字符串变量相关函数

目录 一、变量命名规则 二、字符串变量及相关函数 1、字符串变量 2、相关函数 最后琐碎杂物&#xff1a; 1、字符串之间的拼接 2、字符串格式控制&#xff08;制表符和换行&#xff09; 一、变量命名规则 正如其他编程语言一样&#xff0c;程序离不开声明变量&#x…

三、Python第三课——Python中数字的用法及编码原则(Python禅意)

目录 一、Python中的数字 1、整数 2、浮点数 3、整数、浮点数和字符串的联系和区别 二、编码原则 1、为代码增加注释 2、Python 禅意 A、编码精美 B、避繁就简 C、无简就繁 D、使用常规方法解决问题 E、先有效、再精巧、逐步升华 一、Python中的数字 编程中&#…

四、Python第四课——Python中列表及其操作(增删改查)

目录 一、Python中的列表 1、列表的定义和赋值 2、列表的使用 二、列表的“增删改查” 1、列表中元素的增加 A、在列表尾添加元素 B、在列表中插入元素 2、列表中“元素的删除” A、使用del语句删除元素 B、使用pop()函数删除元素 C、弹出列表中任何位置元素…

五、Python第五课——Python中组织列表的相关函数

目录 一、用sort()函数对列表进行永久排序 二、用sorted()函数对列表进行临时排序 三、用reverse()函数对列表进行列表原始排序的逆序输出 四、使用len()函数确定列表长度 创建列表后&#xff0c;内部的元素逐渐增多&#xff0c;其排列顺序也是无法预测的&#xff0c;因为…

如何正确下载、安装Codeblocks?

目录 一、Codeblocks的下载 二、Codeblocks的安装 三、Codeblocks的运行 相信很多同学在初学C语言时都会选择一个短小精悍的代码编辑器&#xff0c;如CodeBlocks&#xff08;不说别的了&#xff0c;直接切入正题&#xff09;。 在2020年&#xff08;今年&#xff09;3月份-…

Python:创建列表,其中包含数字1-1000000,为什么Pycharm控制台结果显示不完整?

目录 一、问题描述&#xff08;寻找解决方法的同学直接看“标题二”&#xff09; 二、解决办法 一、问题描述&#xff08;寻找解决方法的同学直接看“标题二”&#xff09; 在学习Python过程中遇到一个这样的问题&#xff0c;也算是一个小BUG吧。题目大意是这样的&#xff…

六、Python第六课——Python中的for循环及数字列表

目录 一、Python中的for循环 1、for循环语句的声明。 2、for循环缩进常见问题 二、数字列表 1、函数range() 2、使用range()函数创建数字列表 3、使用一系列函数处理数字列表&#xff08;统计&#xff09; 4、列表解析&#xff08;生成列表的简洁方法&#xff09; 一…

七、Python第七课——有关列表的二三事(切片、切片的遍历和复制)

目录 一、切片 二、遍历切片 三、列表的复制 一、切片 此前&#xff0c;我们学习了如何访问单个列表以及如何处理列表中的所有元素&#xff0c;那么我们如何处理列表中的部分元素呢&#xff1f;这就引出一个概念“切片” 。我们可以把列表看成是面包&#xff0c;“切片”…

八、Python第八课——元组与列表、代码格式

&#xff08;请先看置顶博文&#xff09;https://blog.csdn.net/GenuineMonster/article/details/104495419 目录 一、元组的定义 二、元组的遍历 三、代码格式 一、元组的定义 1、元组&#xff1a;不可变的列表称为元组。这个是相对于普通列表而言的&#xff0c;普通列表…

九、Python第九课——Python中的if语句与运用

&#xff08;请先看置顶博文&#xff09;https://blog.csdn.net/GenuineMonster/article/details/104495419 目录 一、if语句 1、检查变量存储的值是否相等 2、判定字母或字符串时区别大小写 3、检查多个条件 4、检查特定值是否在列表中 二、if-else语句和if-elif-el…

十、Python第十课——字典的些许知识(重点)

&#xff08;请先看置顶博文&#xff09;https://blog.csdn.net/GenuineMonster/article/details/104495419 目录 &#xff08;请先看置顶博文&#xff09;https://blog.csdn.net/GenuineMonster/article/details/104495419 初识字典 1、创建字典 2、字典的“增删改查” …

百度地图API如何申请?(自认为比较详细,如解决了你的问题请收藏、点赞、关注)

&#xff08;请先看置顶博文&#xff09;本博打开方式&#xff0c;请详读_liO_Oil的博客-CSDN博客_怎么把androidstudio卸载干净 注意&#xff1a;自己申请的AK要保存好&#xff0c;最好不要外借&#xff0c;避免不必要的麻烦&#xff01;&#xff08;写在前面&#xff09; 目…