01背包

 

初学者学DP的时候都会接触到背包问题吧哈哈,我理解起来是真的费劲不过坚持就是胜利,让我们一起来学习吧!

首先我看过y总的课,Acwing.com y总背包讲的很好,其中他提供给我了一种去分析动态规划的一种思考方式,我觉得很好。

 

 

 

我们要考虑一道题中,他的状态表示,和状态表达。

而状态表示中,又分为他的集合,和属性。

在01背包中状态表示就会用一个f[i][j]来表示,那在这个集合中,表示我能用到的所有选法,然后条件就是我只能在前i个物品中选,总体积小于等于j的情况下我们所有选法的最大价值,因为01背包中要求最大价值。

然后属性,就是最大值Max

再看如何计算状态,就要看看集合的划分,

当我们的背包容量够的时候,也就是j>=v[i]的时候我们就可以选上第i件物品。那我们就可以这么表示f[i-1][j-v[i]]+w[i],这个式子的意思就是本来可以拿上i物品是吧,应该是f[i][j],但是在大佬们的努力下发现这样算就会很麻烦,所以我们可以这样,i-1之后,就说明我们把第i件物品拿出来了,那么j也要减去i物品的体积对吧,因为我们选不上i了,说以j-v[i],也就是减去第i件物品的体积,那我们减去了i,是不是还要给他加回来,所以后面再加上他的价值w[i],所以综上所述,f[i-1][j-v[i]]+w[i];

那么如果第i件物品大于了j的体积,就选不上i了,所以f[i][j]就等于f[i-1][j];

那么我们的状态计算就表示清楚了,接下来就该看代码了。

那为什么我们要讲二维的方法呢,有些人说不是有一维的办法吗,因为一维的办法是从二维的办法中优化得到的,所以我们一定要了解到他的朴素算法,再去进行优化,我们小白要从他的思维方式一步步的学习他。

#include<iostream>

using namespace std;

const int N = 1011;

int n,m;
int v[N],w[N];
int f[N][N];

int main()
{
    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=0;j<=m;j++)
        {
            f[i][j]=f[i-1][j];
            if(j>=v[i]) f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
        }
    
    cout << f[n][m] << endl;
    return 0;
}

 这里也给出一维数组的解决方法。

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, m;
int v[N], w[N];
int f[N];

int main()
{
    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 >= v[i]; j -- )
            f[j] = max(f[j], f[j - v[i]] + w[i]);

    cout << f[m] << endl;

    return 0;
}

 

posted @ 2020-02-25 21:41  zust-lms  阅读(173)  评论(0编辑  收藏  举报