01背包问题

题目链接

01背包

题目描述

已知一个背包最多能容纳物体的体积为V
现有n个物品第i个物品的体积为v_iv
i

第i个物品的重量为w_iw
i

求当前背包最多能装多大重量的物品

示例1

输入

10,2,[[1,3],[10,4]]

输出

4

说明

第一个物品的体积为1,重量为3,第二个物品的体积为10,重量为4。只取第二个物品可以达到最优方案,取物重量为4 

备注:

1≤V≤200
1≤n≤200
1≤v≤200
1≤w≤200

解题思路

对于动态规划问题,我们首先需要搞清楚【状态】和【选择】是什么?

这道题涉及到的变化的状态量有两个,就是背包的体积和当前可选的物品,选择就是把物体装进背包或者不装进背包。

这样就可以定义我们的dp数组了.

1. 定义dp数组

首先两个状态量就是二维dp数组的两个维度。

dp[i][j]=x表示对于前i个物体,当前背包的体积为j,这种情况下可以装的最大重量是dp[i][j]

这里的定义可能并不直观,但是这是背包问题的典型套路,记住就行了

2. 确定base case

物体个数为0或者背包体积为0时可以装的物体重量都为0,即

dp[0][...]=0,dp[...][0]=0

3. 推导状态转移方程

推导状态转移方程本质就是做选择,也就是把第i个物体放入或者不放入背包,然后做最优选择就行了

dp[i][j] = max(dp[i-1][j], dp[i-1][j-vw[i-1][0]] + vw[i-1][1])

这里需要注意的是数组的下标,由于i是从1开始的,所以题目中的给的数组下标为i-1时表示的是第i个物品的重量。

题解

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 * 计算01背包问题的结果
 * @param V int整型 背包的体积
 * @param n int整型 物品的个数
 * @param vw int整型二维数组 第一维度为n,第二维度为2的二维数组,vw[i][0],vw[i][1]分别描述i+1个物品的vi,wi
 * @return int整型
*/
func knapsack(V int ,n int ,vw [][]int ) int {
	// 定义dp数组,dp[i][j]表示对于前i个物体,当前背包体积为j,最多可以装多大重量的物体
	dp := make([][]int, n+1)
	for i := 0; i <= n ; i++ {
		// 定义base case
		// 物体个数为0或者背包体积为0时可以装的物体重量都为0,即
		// dp[0][...]=0,dp[...][0]=0这个已经自动初始化好了
		dp[i] = make([]int, V+1)
	}

	// 推导状态转移方程
	// 按照物体数量进行遍历
	for i := 1; i <= n; i++ {
		// 按照背包可用体积进行遍历
		for j := 1; j <= V; j++ {
			// 背包体积已经不够装第i个物体了,只能不装入背包
			if j - vw[i-1][0] < 0 {
				dp[i][j] = dp[i-1][j]
			} else {
				// 可以选择装入或不装入,取较大值
				dp[i][j] = max(dp[i-1][j], dp[i-1][j-vw[i-1][0]] + vw[i-1][1])
			}
		}
	}
	return dp[n][V]
}

复杂度分析

时间复杂度:O(C*N)

假设物品的个数为N, 背包的容量是C,两层循环,所以算法的总时间复杂度是 O(C*N)

空间复杂度:O(C*N)

需要开辟一个为C*N大小的dp数组。

反思

背包问题是非常经典的动态规划问题,这是最基本的问题,先熟悉一下套路。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值