动态规划一日一题-10.5-01背包问题



01背包问题

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

第 i件物品的体积是 vi,价值是 wi。

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

输入格式

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

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式

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

数据范围

0<N,V≤1000
0<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

8

还是用之前的分析方法来分析:

状态表示:f[i] [j] 表示使用前i个物品,且总体积不大于j的时候,所实现的最大价值

状态属性:max

base case:f[i] [0] = 0 ; f[0] [i] = 0 (因为此题的base case来说,我们申请dp数组的时候就是申请的全局变量,默认值直接是0,所以这一题的base case没有显性的展现出来)。

状态转移:分成两块,任何状态都可以分成两个状态,一是不使用第i个物品,二是使用第i件物品。分隔条件是v[i] 与j的大小关系。

代码如下:

#include

using namespace std ;

const int N = 1010 ; 

int f[N][N] ;

int w[N] , v[N] ;
int main()
{
    int n , m ; 
    
    cin >> n >> m ; 
    
    for(int i = 1 ; i <= n ; ++i)
    {
        cin >> v[i] >> w[i] ;
    }
    
    
    for(int i = 1 ; i <= n ; ++i)
    {
        for(int j = 1 ; j <= m ;++j)
        {
            f[i][j] = f[i-1][j] ;
            if(v[i] <= j)
            {
                f[i][j] = max(f[i][j] , f[i-1][j-v[i]]  + w[i]) ;
            }
        }
    }
    cout << f[n][m] << endl ;
    return  0 ; 
}

仔细阅读上述代码之后,我们发现可以采用一维数组进行优化。因为i在这题来说,可以根据循环的由小到大的次序进行省略。

其中有一个比较难理解的点就是,对于二层循环的j来说,不应该是有小到大进行穷举,而是应该是由大到小进行穷举,因为对于二维代码来说,有一个i用来指向此时的j是上一次的循环的还是下一次循环的,状态转移是由上一次循环转移来的,所以不管j是大还是小,都是上一次循环来赋值的。但是对于一维的dp数组来说,没有i作为指向,必须通过j的列举顺序来体现是上一轮循环的状态转移。

当然,最简单的理解就是一维的dp方法必须要满足二维的dp方法的逻辑思路。所以对于j的列举顺序必须满足,f[j]的状态必须是上次循环中j的值比现在小的dp值转移过来的。

所以,根据这一条原则,j如果不变化,仍然是由小到大进行列举的话,虽然是由比自己小的j的dp值转移过来的,但是这些值都是由本轮循环进行迭代之后得到的值,并不是上一轮循环所遗留下来的,这就导致了逻辑出现了错误。

优化空间后的代码如下:

#include

using namespace std ;

const int N = 1010 ; 

int f[N] ;

int w[N] , v[N] ;
int main()
{
    int n , m ; 
    
    cin >> n >> m ; 
    
    for(int i = 1 ; i <= n ; ++i)
    {
        cin >> v[i] >> w[i] ;
    }
    
    
    for(int i = 1 ; i <= n ; ++i)
    {
        for(int j = m ; j >= 0 ; --j)
        {
            if(v[i] <= j)
            {
                f[j] = max(f[j] , f[j-v[i]]  + w[i]) ;
            }
        }
    }
    
    cout << f[m] << endl ;
    
    return  0 ; 
}

文章作者: 罗林
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 罗林 !
  目录