【动态规划】01背包问题

题目

题目描述

N N N 件物品和一个容量是 V V V 的背包。每件物品只能使用一次。

i i i 件物品的体积是 v i v_i vi,价值是 w i w_i wi

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数, N , V N,V NV,用空格隔开,分别表示物品数量和背包容积。

接下来有 N N N 行,每行两个整数 v _ i , w _ i v\_i, w\_i v_i,w_i,用空格隔开,分别表示第 i i i 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N , V ≤ 1000 0 \lt N, V \le 1000 0<N,V1000
0 < v i , w i ≤ 1000 0\lt v_i, w_i \le 1000 0<vi,wi1000

输入样例

4 5
1 2
2 4
3 4
4 5
输出样例:
8

思路

我们用动态规划解决问题时需要经过如下几个步骤:

  1. 确定动态规划的状态表示,即 d p dp dp 数组所代表的含义。

  2. 根据第1步确定的状态表示来推想动态规划转移方程。

  3. 分析时间复杂度,如果复杂度不在我们允许的范围之内,尝试优化动态规划转移复杂度或重新定义状态表示。

对于这道01背包问题,我们执行以下步骤:

  1. d p [ i ] [ j ] dp[i][j] dp[i][j]表示在前 i i i 件物品里选出若干件,且物品体积和不超过 j j j 能取到物品的最大价值。若我们可以求解出 d p dp dp 数组,则 d p [ N ] [ V ] dp[N][V] dp[N][V] 就是我们要求的答案了。
  2. 考虑如何求得 d p [ i ] [ j ] dp[i][j] dp[i][j]。根据我们定义的状态, d p [ i ] [ j ] dp[i][j] dp[i][j] 表示在前 i i i 件物品中选取若干件体积和不超过 j j j 的最大价值,因此 d p [ i ] [ j ] dp[i][j] dp[i][j] d p [ i − 1 ] [   ] dp[i - 1][\ ] dp[i1][ ] 的差别只在于第 i i i 件物品在 d p [ i − 1 ] [   ] dp[i - 1][\ ] dp[i1][ ] 没被考虑,所以我们可以通过 d p [ i − 1 ] [   ] dp[i - 1][\ ] dp[i1][ ] 推出 d p [ i ] [ j ] dp[i][j] dp[i][j]
    接下来分别考虑第 i i i 件物品选或不选。
    如果我们选择第 i i i 件物品,那么从前 i − 1 i - 1 i1 种物品中选出的体积就不能超过 j − v i j - v_i jvi ,所能得到的最大价值为 d p [ i − 1 ] [ j − v i ] + w [ i ] dp[i - 1][j - v_i] + w[i] dp[i1][jvi]+w[i]
    若不选择第 i i i 件物品,则延续之前的最大价值,最大价值为 d p [ i − 1 [ [ j ] dp[i - 1[[j] dp[i1[[j]
    取这两种情况的最大值;因此,我们的状态转移方程为:
    d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − v i ] + w i ) dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v_i] + w_i) dp[i][j]=max(dp[i1][j],dp[i1][jvi]+wi)
    注意:我们需要保证目前枚举到的 j j j 是大于等于当前物品体积的,否则说明现在的状态背包根本就装不下这个物品,只能延续之前的最大价值。
  3. 计算时间复杂度:我们不难发现,求解单个状态的复杂度仅为 O ( 1 ) O(1) O(1);所以总时间复杂度则为状态数 O ( N V ) O(NV) O(NV)

代码

#include <iostream>
#include <cstring>
using namespace std;
const int N = 1010, M = 1010;
int n, V;
int v[N], w[N];
int dp[N][M];
int main() {
	cin >> n >> V;
	for (int i = 1; i <= n; ++ i ) cin >> v[i] >> w[i];
	for (int i = 1; i <= n; ++ i ) 
		for (int j = 0; j <= V; ++ j ) 
			if (j >= v[i]) dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
			else dp[i][j] = dp[i - 1][j];
	cout << dp[n][V] << '\n';
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值