vlambda博客
学习文章列表

01背包—起步动态规划的初级攻略,小王子想带走公主要先解决了这道题!!!

小王子立即收拾好东西出发,要去救公主(公主又被恶龙抓走啦)。小王子到恶龙的山上,恶龙对小王子说:“打架每一次都是你赢,我要和你换一种方式决斗。现在我这里有一些宝石,给你一个能容纳10KGM)重量的背包,这里有5个(N)宝石,每个宝石对应不同的价值,你如果能够写出一个程序在时间限制500ms内存限制65536KB计算出如何装宝石能够让背包的价值最大,我以我的龙格保证放了你的公主”。

小王子看了一下地上的宝石,分别是1KG3KG5KG7KG10KG,价值(如图)

01背包—起步动态规划的初级攻略,小王子想带走公主要先解决了这道题!!!

小王子微微一笑:“这有何难?”
你知道小王子怎么写出程序救走公主的吗?

一、题目思考

对于这道题,首先可能会想到暴力枚举,但是暴力方式计算量实在太大,有超时的风险。我们应该想一个简单快捷的办法,恶龙只要求我们说出最终能够实现的最大价值,而不需要实现最大价值的组合顺序。这么说来,就应该用动态规划解决问题。

前面说过,小王子的包现在只能承受10KG的重量,若干宝石有自己的价值和重量,只需要选择放或者不放,问装载宝石产生的最大价值问题,就是一个典型的动态规划里面的01背包问题。其实这是一个很简单的问题,只是对于初学者来说第一次使用的时候思考可能会有一点点的绕弯。下面我们一起分析一下解题过程

二、解题过程

为了清晰表述和理解,我们首先需要分配一个二维数组为a[N][M+1],如题所述为a[5][11],得到数组之后(初始化情况请看下图),我们开始在这个数组中填入数据,下面是分析过程

我们假设我们面前只有一块宝石就是第一块,那么利用背包不同容量会得到多大价值呢?很明显因为1KG宝石的价值是1,不论多少容量能达到的最大价值都是1,所以我们应该如此填充数组。

01背包—起步动态规划的初级攻略,小王子想带走公主要先解决了这道题!!!


这时候数组表示在对于不同的背包剩余容量时候,只容纳第一块宝石的最优解。下面我们开始考虑只有两块宝石而且是前两块时候的不同状态的最大价值。不再列举数字字母,下面是纯逻辑叙述。从A[2][1]开始,横坐标为当前剩余容量。当剩余容量为1时,第二块宝石无法容纳,所以此时最大价值还是1。当剩余容量为3时,第二块宝石可以装进去,但是我们如何考虑是不是要装进去呢?我们开始思考,2号宝石的质量是3,如果装进去就能在当前容量内达到最高价值4而不是1,很明显此时的4为最优解。填入得

01背包—起步动态规划的初级攻略,小王子想带走公主要先解决了这道题!!!

三、转移方程(核心)

可是只是逻辑思考是不够的,我们要有一个比较,这就是状态转移方程,设第i个宝石重量为W,价值为P,当剩余空间为V时,则

A[i][V]=min{A[i-1][V],A[i-1][V-W]+P}

大括号里分两个部分,前面是如果不放入当前宝石所能产生的最大价值,后面相反。对于后者,我们可以这么理解:我们如果把这块宝石放进去,或多或少会有剩余空间(否则根本不必考虑),那么这剩余的空间所能够容纳的最高价值是多少呢?这个剩余空间肯定小于当前空间,对于这个剩余空间的最优解,我们之前已经计算过的,在此处:2号宝石质量为3,价值为4。当容量为3的时候,如果不放入2号宝石最大价值为a[1][3],就是1。如果放入2号宝石,那么最大价值经过上述公式计算可以得出为A[2-1][3-3]+4=0+4=4,  A[2][3]=4

同理,当容量为4的时候,如果不放入2号宝石最大价值为a[1][4],就是1。如果放入2号宝石,那么最大价值经过上述公式计算可以得出为A[2-1][4-3]+4=1+4=5,  A[2][3]=5

以此类推,可得第二列。

01背包—起步动态规划的初级攻略,小王子想带走公主要先解决了这道题!!!

同时,我们可以计算出表格的全部内容

01背包—起步动态规划的初级攻略,小王子想带走公主要先解决了这道题!!!

所以在题目要求下最高价值是20,解题完毕。小王子这就可以把公主领走啦!


下面是代码部分


四、代码实践(C语言)

#include<stdio.h>int max(int x,int y);int main(void){ int n,m,k,a[1000],b[100][2],i,j,shi,jia; printf("请输入背包容量:\n") ;  scanf("%d",&n); printf("请输入宝石个数:\n") ;  scanf("%d",&m);
for(i=0;i<=n;i++) a[i]=0; printf("请逐个输入宝石的质量和价值:\n") ; for(i=0;i<m;i++){
scanf("%d%d",&shi,&jia); for(j=n;j>=shi;j--){ a[j]=max(a[j],a[j-shi]+jia); } }

printf("可以实现的宝石最大价值为%d",a[n]);
}int max(int x,int y){ if(x>y) return x; return y;}







往期精彩回顾


近日以来防疫形势严峻,同学们应当停留家中尽量不要外出走动。勤通风,勤洗手,注意个人卫生,不要熬夜,早睡早起提高身体免疫力!祝大家身体健康,祝武汉早日渡过难关!

01背包—起步动态规划的初级攻略,小王子想带走公主要先解决了这道题!!!
武汉加油!



点“在看”会有好事发生哦!