【数据结构与算法】01背包问题及输出具体方案

背景

最近重新复习下动态规划相关知识,所以把经典的背包问题拿出来重新看下。最为经典的莫过于背包九讲,详见:
这里只是把自己在做的过程中一些想法记录下来。

本文主要描述01背包问题。背包问题指的是我们有多少件物品要放进背包,求放进背包的价值最大。而01背包指的是每个种类的物品只有1件。

让我们看下具体问题

现在有三件物品,笔记本、手机跟手表。每件物品重量跟价值如下:

物品笔记本手机手表
重量3kg1kg1kg
价值200050003000

现有一个4kg的背包,请问要怎么分配空间,使得整体价值最大。

解题思路

动态规划的思路实际就是把大的问题拆分成小的问题,
这里我们先定义状态:dp[i][j],把前i个物品放到容量为j的背包里的最大价值。
那么有:
1)如果第i件物品,我们选择放到背包里(背包有足够容量j-weight[i]>0):
dp[i][j] = max(dp[i-1][j] , dp[i-1][j-weight[i]] + value[i])
2)不放到背包里:
dp[i][j] = dp[i-1][j]
按照这个思路,遍历 i:1-3,j:1-4
i=0,j=0~4,这是不管背包多少重量,都没有价值,所以dp[0][j] = 0。这也是dp[][]的初始状态,相当于这里进行了初始化。
i=1,这时我们看下笔记本时,背包重量从1到4的时候,背包里面的最大价值会是多少。
i=1,j=1或2,背包无法放下笔记本,dp[1][1] = dp[1][2] = 0
i=1,j=3,背包能放下笔记本,dp[1][3] = dp[0][3-1] + value[0] = 2000
同理,i=1,j=4时,dp[1][4] = dp[0][4-1] + value[0] = 2000
那么我们得到:

1234
笔记本0020002000
手机
手表

i=2,这时我们手里有笔记本及手机,背包重量从1到4,背包里面最大价值会是多少。
i=2,j=1时,背包无法放下笔记本,只能放下手机,这时dp[2][1] = dp[1][1-1] +value[2] = 5000
同理,i=2,j=2时, dp[2][2] = dp[1][2-1] +value[2] = 5000
i=2,j=3时, 背包可以放下笔记本或者手机,但无法同时存放,那么我们要对比具体价值大小: dp[2][3] = max(dp[1][3],dp[1][3-1] +value[2]) = max(2000,5000),得到只能存放手机
i=2,j=4时,背包可以放下笔记本和手机。
这时的表格变成:

1234
笔记本0020002000
手机5000500050007000
手表

i=3,这时我们手里有笔记本及手机、手表,背包重量从1到4,背包里面最大价值会是多少。
i=3,j=1时,背包无法放下笔记本,只能放下手机或手表,这时dp[3][1] =max(dp[2][1],dp[2][0]+value[3])=max(5000,3000) = 5000
这里成立的原因是,我们已经得到了dp[2][1],这个值已经被更新为前2个物品在1kg背包时的最大价值,再加上第三个对比即可。
因此,我们也可以得到其他情况:

1234
笔记本0020002000
手机5000500050007000
手表5000800080008000

代码实现

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
#define MAX 10
int getMax(int x,int y){
	return x>y?x:y;
}
int getValue(int m,int n,int *weight,int *value){

	int dp[MAX][MAX];
	for(int i=0;i<=m;i++){
		for(int j=0;j<=n;j++){
			dp[i][j]=0;
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			if(j>=weight[i-1]){
				dp[i][j]=getMax( dp[i-1][j],dp[i-1][j-weight[i-1]]+value[i-1] );		//这里要注意我们取得都是weight[i-1] value[i-1] 因为这里的数据是按0开始存放。
			}else{
				dp[i][j] = dp[i-1][j];
			}
		}
	}
	int maxValue = dp[m][n];
	
	return maxValue; 
}


int main(int argc, char** argv) {
	
	
	int m = 3;
	int n = 4;
	int weight[]={3,1,1};
	int value[]={2000,5000,3000};
	
	int res = getValue(m,n,weight,value);
	
	cout<<"value:"<<res<<endl;
	return 0;
}

运行得到:
value:8000

如何得到具体的方案

按照最大价值的思路,做个逆向运算即可。即:
我们得到了整个表dp[][],现在我们遍历所有的物品i,看下是否有选中具体的某一件。
如何判断有没有选中物品i,根据我们上面的条件,如果选择放某一件物品i,具体的dp会更新如下:
dp[i][j] = dp[i-1][j-weight[i]] + value[i]
那么判断上述这个等式如果成立的话,也就是选中了i,
编写对应代码验证看看:

	int restj = n;
	for(int i=m;i>0;i--){
		for(int j=restj;j>0;j--){
			if(dp[i][j]==dp[i-1][j-weight[i-1]]+value[i-1]){
				restj -= weight[i-1];
				cout<< "pick:"<<i<<" restj:"<<restj<<endl;
				break;
			}
		}
	}
	

运行得到:
pick:3 restj:3
pick:2 restj:2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构与算法设计项目01背包问题是指在算法设计与分析课程中,学生需要解决一个背包问题。该问题要求在给定的一组物品和背包容量的情况下,选择一些物品放入背包中,使得被选中物品的总价值最大化,同时保证它们的总重量不超过背包的容量。 在数据结构与算法课程设计实验中,学生通常会进行一系列实践项目,比如定时/计数技术应用程序设计、图形变换程序设计、代码转换程序设计等。这些项目旨在帮助学生巩固和应用所学的数据结构与算法知识,提高他们的编程能力和解决实际问题的能力。在解决01背包问题的项目中,学生需要设计和实现一个算法,以有效地选择物品放入背包,从而达到最优化的目标。 为了解决01背包问题,学生可以使用动态规划算法。这种算法通过建立一个二维数组来存储子问题的解,并利用子问题的解来构建更大规模的问题的解。具体来说,学生可以先初始化一个二维数组,然后使用循环遍历物品和背包容量的组合,并根据当前物品的重量和价值来更新数组中对应位置的值。通过动态规划算法,学生可以找到最优解,即选择哪些物品放入背包以达到最大的总价值。 除了动态规划算法,学生还可以尝试其他的算法来解决01背包问题,比如贪心算法和回溯算法。贪心算法通过选择当前最优解来构建整体最优解,而回溯算法则通过穷举所有可能的解来找到最优解。每种算法都有其优缺点,学生可以根据实际情况选择合适的算法来解决01背包问题。 总之,数据结构与算法设计项目01背包问题是一个让学生应用所学知识解决实际问题的项目。学生可以使用动态规划算法或其他算法来解决该问题,并通过编程实践提高自己的算法设计和分析能力。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [算法设计与分析课程的背包问题](https://download.csdn.net/download/you_best_honor/12924018)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [数据结构与算法课程设计报告](https://download.csdn.net/download/nibashangtian/10164603)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值