背包问题(01背包)
--------开始--------
每次用到背包问题就忘,今天特意把背包问题写下来,本篇只写01背包问题,至于其它的背包问题以后会陆续出现,大多数背包问题都是以01背包为原型来演变过来的,所以先介绍经典的01背包问题。
01背包问题是动态规划的典型例题,0 1顾名思义就是一个物品有两种情况,拿或者不拿,每种物品有且仅有一件,用子问题定义状态:即f[i][j]表示前i件物品恰放入一个容量为j的背包可以获得的最大价值。则其状态转移方程便是:
f[i][j]=max( f[i-1][j],f[i-1][j-v[i]]+w[i] )
至于这个方程怎么推导出来的,我后面会介绍,总之,这个状态转移方程特别重要,其它背包问题的状态转移方程也都是又它衍生出来的,可以说它的作用非常重要。
我们先来看下01背包的题目 :
问题
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi ,价值是 wi 。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi , wi ,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤10000<N,V≤1000
0<vi,wi≤1000
输入样例
4 5 1 2 2 4 3 4 4 5
输出样例:
8
问题特点很明确:每件物品只有一件我们可以选择拿或者不拿,我们定义v[ i ]为物品的体积,w[i]为物品的价值。
我们再来看状态转移方程 f[ i ][ j ] = max ( f[ i-1 ][ j ] , f[ i-1 ][ j-v[ i ] ] + w[ i ] )
f[i][j]就是前i件物品,在体积为j的情况下最大价值是多少。
我们要计算在有限空间中怎么才能价值最大,可以通过转化求在n件物品和n-1件物品(放第n件物品或者不放)中求最大价值,所以我们需要求n-1件物品时的最大价值,进而类似递归需要求n-1件物品和n-2件物品中的最大值,一直到最后一件,从第一件推回第n件就是我们的结果。
1. 选第i件物品 f[i][j] = f[i - 1][j - v[i]] ;
2. 不选第i件物品 f[i][j] = f[i - 1][j] ;
然后我们的答案就是res = max{ f[n][0~ V] } ;
for(int i = 1;i <= n;i++) for(int j = 0;j <= m;j++) { f[i][j] = f[i-1][j]; if(j >= v[i]) f[i][j] = max(f[i-1][j-v[i]]+w[i],f[i][j]); } int res=0; for(int i =0;i <= m;i++) res = max(res,f[n][i]);
以上描述的方法的时间和空间复杂度均为O(VN),但是时间复杂度应该已经不能再优化了,而空间复杂度却可以优化到O(V),即可以把二维数组变成一维数组,至于如何优化会在下次再继续讲解。
PS : 题目来源: https://www.acwing.com/problem/content/2/
参考文章: https://blog.csdn.net/u013445530/article/details/40210587
--------结束--------