【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析

这篇具有很好参考价值的文章主要介绍了【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

动态规划

动态规划就像是解决问题的一种策略,它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题,并将每个小问题的解保存起来。这样,当我们需要解决原始问题的时候,我们就可以直接利用已经计算好的小问题的解,而不需要重复计算。

动态规划与数学归纳法思想上十分相似。

数学归纳法:

  1. 基础步骤(base case):首先证明命题在最小的基础情况下成立。通常这是一个较简单的情况,可以直接验证命题是否成立。

  2. 归纳步骤(inductive step):假设命题在某个情况下成立,然后证明在下一个情况下也成立。这个证明可以通过推理推断出结论或使用一些已知的规律来得到。

通过反复迭代归纳步骤,我们可以推导出命题在所有情况下成立的结论。

动态规划:

  1. 状态表示:

  2. 状态转移方程:

  3. 初始化:

  4. 填表顺序:

  5. 返回值:

数学归纳法的基础步骤相当于动态规划中初始化步骤。

数学归纳法的归纳步骤相当于动态规划中推导状态转移方程。

动态规划的思想和数学归纳法思想类似。

在动态规划中,首先得到状态在最小的基础情况下的值,然后通过状态转移方程,得到下一个状态的值,反复迭代,最终得到我们期望的状态下的值。

接下来我们通过三道例题,深入理解动态规划思想,以及实现动态规划的具体步骤。

DP41 【模板】01背包

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

题目解析

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

第一问

状态表示

状态表示通常由经验+题目要求得的。

我们最容易想到的状态表示是,定义dp[i]表示从前i个物品中挑选,背包所能达到的最大价值。

动态规划最重要的是希望能够推导出一个递推式,使得我们从一个很小的,很容易得到的基础解,带入递推式,反复推导,最后得到我们希望得到的答案。所以我们很容易想到,根据从前i个物品中挑选,挑选物品的数量,构成我们的每一项,希望能够推导出递推式。

如果我们要推导dp[i],我们找不到前面状态和i位置状态的关系,我们知道的信息是前面位置状态的值,状态值表示所能达到的最大价值,但是我不知道达到最大价值时,背包的容量,所以我就没办法考虑是否选择第i个物品放入背包,或者不放入背包,如果我们此时还知道对应的背包容量,如果还有位置,我们就可以选择把第i个物品放进去,这样似乎可以推导出状态转移方程。所以此时我们还需要表示一个状态,就是此时背包内物品占用的空间是多大。

因此我们可以定义,f[i]表示从前i个物品中挑选,背包所能达到的最大价值。g[i]表示从从前i个物品中挑选,背包所能达到的最大价值时,背包占用的体积。

尝试推导状态转移方程,

  1. 如果把第i个物品放入背包, 此时g[i-1]+v[i]<=V , 此时从前i个物品挑选,所能达到的最大价值,等价于从前i-1个物品挑选,所能达到的最大价值加上第i个物品的价值,即在f[i]的基础上,把第i个物品放入背包,此时f[i]=f[i-1]+w[i],g[i]=g[i-1]+v[i]。

  2. 如果不把第i个物品放入背包, 此时g[i-1]+v[i]>V, 此时f[i]=f[i-1],g[i]=g[i-1],这样写是对的吗?乍一看好像没什么问题,但这样不对,有可能从前i-1个物品中挑选,达到的价值不是最大,而是第二大,此时的体积再加上第i个位置的物品的体积比背包总体积小,但是两者价值加起来比f[i-1]大,这种情况f[i]!=f[i-1]。也就是我们还需要遍历前面所有状态,看看是不是(g[j]+v[i]<=V)这种情况,如果是,记录一下f[j]的值,找到最大的f[j]值,然后和f[i-1]比较,选大的值。这样状态转移方程的推导就变得十分麻烦,我们希望改变状态表示,使得状态转移方程能够正常推导,并且简便。

改进,

上面遇到的问题是,我们不知道,从前i-1物品挑选,价值和第二大的体积花费,价值和第三大的体积花费......如果知道这些状态,我们就可以直接用。

我们需要的状态是上面的体积花费,因此我们可以以体积为划分,定义dp[i][j]表示从前i个物品中挑选,总体积不超过j,所有选法中,所能达到的最大价值。

这样我们就使得原先只能存储最大价值的体积g,转变为可以存储不同体积花费的二维dp。

综上所述,状态表示为,定义dp[i][j]表示从前i个物品中挑选,总体积不超过j,所有选法中,所能达到的最大价值。

状态转移方程

  1. 如果把第i个物品放入背包, dp[i][j]表示从前i个物品中挑选,总体积不超过j,所有选法中,所能达到的最大价值。此时剩下的体积最多是j-v[i]。

    1. j-v[i]<0, 此时没办法把第i个物品放入背包,此时dp[i][j]=0。

    2. j-v[i]=0, 此时把第i个物品放入背包,背包放不下东西了,此时dp[i][j]=w[i]。

    3. j-v[i]>0, 此时把第i个物品放入背包,背包还能放j-v[i]体积的物品,此时dp[i][j]=dp[i-1][j-v[i]]+w[i]。

  2. 如果不把第i个物品放入背包, 此时背包还能放j体积的物品,从前i-1物品中挑选,dp[i][j]=dp[i-1][j],

当j-v[i]=0时,dp[i-1][0]=0,此时dp[i][j]=dp[i-1][j-v[i]]+w[i]。

将上述情况合并和简化,得到状态转移方程为,

 
    dp[i][j] = dp[i - 1][j];
    if (j >= v[i])
        dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);

初始化

通过状态转移方程,我们我们知道在推导(i,j)位置的状态时,需要用到(i-1,j)(i-1,j-v[i])的位置的状态,j-v[i]一定不会越界,可能越界的是i-1,而我们状态表示为定义dp[i][j]表示从前i个物品中挑选,总体积不超过j,所有选法中,所能达到的最大价值。所以我们本质上多添加了一列。我们只需要初始第一行即可。

i=0表示不选物品,所以价值都为0,第一行全部初始化为0。

填表顺序

通过状态转移方程,我们我们知道在推导(i,j)位置的状态时,需要用到(i-1,j)(i-1,j-v[i])的位置的状态,j-v[i]一定不会越界。

  1. 固定i改变j, i的变化需要从小到大,j的变化可以从小到大也可以从大到小。

  2. 固定j改变i, j的变化需要从小到大,因为要用到(i-1,j)位置的状态,所以i的变化也需要从小到大。

返回值

状态表示为定义dp[i][j]表示从前i个物品中挑选,总体积不超过j,所有选法中,所能达到的最大价值。

结合题目意思,需要打印dp[n][V]。

这样我们就解决了第一问。


第二问

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

状态表示

第二问需要求恰好体积为V时,背包所能达到的最大价值。

在第一问的基础上,我们很容易定义这样一个状态表示,定义dp[i][j]表示从前i个物品中挑选,总体积恰好为j,所有选法中所能达到的最大价值。

状态转移方程

  1. 如果把第i个物品放入背包, dp[i][j]表示从前i个物品中挑选,总体积恰好为j,所有选法中所能达到的最大价值。此时剩下的体积恰好是j-v[i]。

    1. j-v[i]<0, 此时没办法把第i个物品放入背包,此时dp[i][j]=0。

    2. j-v[i]=0, 此时把第i个物品放入背包,背包放不下东西了,此时dp[i][j]=w[i]。

    3. j-v[i]>0, 此时把第i个物品放入背包,背包还需要放j-v[i]体积的物品,此时dp[i][j]=dp[i-1][j-v[i]]+w[i]。我这样写对吗?此时背包必须放j-v[i]体积的物品,如果前j-1物品挑选不能满足体积为j-v[i]的情况,此时dp[i][j]=0。如果写成上面的式子,dp[i][j]=w[i]。因此我们还需要分类讨论。

      1. 如果前j-1物品挑选不能满足体积为j-v[i]的情况, 此时dp[i][j]=0。

      2. 如果前j-1物品挑选能满足体积为j-v[i]的情况, 此时dp[i][j]=d[i-1][j-v[i]]+w[i]。

  2. 如果不把第i个物品放入背包, 此时背包还需要放j体积的物品,从前i-1物品中挑选,dp[i][j]=dp[i-1][j]。

当j-v[i]=0时,dp[i-1][0]=0,此时dp[i][j]=dp[i-1][j-v[i]]+w[i]。

将上述情况进行合并和简化,得到状态转移方程,

 
        dp[i][j] = dp[i - 1][j];
        if (j >= v[i] && dp[i - 1][j - v[i]] != -1)
            dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);

用-1表示前j-1物品挑选不能满足体积为j-v[i]的情况。

初始化

通过状态转移方程,我们我们知道在推导(i,j)位置的状态时,需要用到(i-1,j)(i-1,j-v[i])的位置的状态,j-v[i]一定不会越界,可能越界的是i-1,而我们状态表示为定义dp[i][j]表示从前i个物品中挑选,总体积不超过j,所有选法中,所能达到的最大价值。所以我们本质上多添加了一列。我们只需要初始第一行即可。

i=0,表示不选择物品,最大价值为0,所以(0,0)为0,其他位置为-1,表示达不到恰好体积为j的情况。

 
    for (int j = 1; j <= V; j++) dp[0][j] = -1;

填表顺序

通过状态转移方程,我们我们知道在推导(i,j)位置的状态时,需要用到(i-1,j)(i-1,j-v[i])的位置的状态,j-v[i]一定不会越界。

  1. 固定i改变j, i的变化需要从小到大,j的变化可以从小到大也可以从大到小。

  2. 固定j改变i, j的变化需要从小到大,因为要用到(i-1,j)位置的状态,所以i的变化也需要从小到大。

返回值

状态表示为定义dp[i][j]表示从前i个物品中挑选,总体积不超过j,所有选法中,所能达到的最大价值。

结合题目意思,需要打印dp[n][V]。此时需要判断dp[n][V]是否==-1,等于-1表示不存在,无解返回0,如果不为-1,返回dp[n][V]。

代码实现

 
#include <iostream>
#include <string.h>

using namespace std;

const int N = 1010;

int n, V, v[N], w[N];
int dp[N][N];

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++) { 
            dp[i][j] = dp[i - 1][j];
            if (j >= v[i])
                dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);
        }

    cout << dp[n][V] << endl;

//第二问
    memset(dp, 0, sizeof dp);
    for (int j = 1; j <= V; j++) dp[0][j] = -1;
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= V; j++) { 
            dp[i][j] = dp[i - 1][j];
            if (j >= v[i] && dp[i - 1][j - v[i]] != -1)
                dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);
        }
    cout << (dp[n][V] == -1 ? 0 : dp[n][V]) << endl;

    return 0;
}

416. 分割等和子集 - 力扣(LeetCode)

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

题目解析

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

状态表示

01背包问题本质是从一些物品中选物品,本质上是有关组合的问题,而本题目也是在一些数中挑选出一些数,因为我们可以以01背包为模版,定义状态表示。

01背包问题的状态表示为,

定义dp[i][j]表示从前i个物品中挑选,总体积不超过j,所有选法中,所能达到的最大价值。

定义dp[i][j]表示从前i个物品中挑选,总体积为j,所有选法中,所能达到的最大价值。

因此我们可以定义dp[i][j]表示能否从nums[0,i]区间中挑选元素,使总数字和为j。

状态转移方程

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

状态转移方程的推导是以最后一个位置的状况进行分类讨论。

  1. 如果挑选i位置的元素,

    1. 如果j-nums[i]<0, 此时表示i位置元素比j还要大,此时dp[i][j]=false;

    2. 如果j-nums[i] =0, 此时dp[i][j]=true;

    3. 如果j-nums[i]>0, 此时dp[i][j]=dp[i-1][j-nums[i]];

  2. 如果不挑选i位置的元素, 此时dp[i][j]=dp[i-1][j];

将上述情况进行合并和简化,得到状态转移方程,

 
        dp[i][j] = dp[i - 1][j];
        if (j > nums[i])
            dp[i][j] = dp[i][j] || dp[i - 1][j - nums[i]];
        else if(j == nums[i]) dp[i][j] = true;

初始化

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

根据状态转移方程,我们知道,在推导(i,j)位置的状态时,需要用到(i-1,j)(i-1,j-nums[i])位置的状态。

所以我们需要初始化第一行位置的状态,在推导蓝色部分位置状态的时候没有前驱,所以需要初始化这些位置的状态值。使用(i-1,j-nums[i])状态时,j-nums[i]一定不会越界。所以只需要考虑(i-1,j)

状态表示,定义dp[i][j]表示能否从nums[0,i]区间中挑选元素,使总数字和为j。

i==0,表示从只选择挑选或者不挑选第一个元素,能否使数字和为j。如果nums[0]==j,或者j==0,此时dp[i][j]=true。

故初始化为,

 
        for (int j = 0; j < n; j++)
            if(nums[0] == j || j == 0) dp[0][j] = true;

填表顺序

根据状态转移方程,我们知道,在推导(i,j)位置的状态时,需要用到(i-1,j)(i-1,j-nums[i])位置的状态。使用(i-1,j-nums[i])状态时,j-nums[i]一定不会越界。所以只需要考虑(i-1,j)

  1. 固定i改变j, i的变化,需要从小到大,j的变化可以从小到大也可以从大到小。

  2. 固定j改变i, j的变化可以从小到大也可以从大到小,i的变化需要从小到大。

返回值

状态表示,定义dp[i][j]表示能否从nums[0,i]区间中挑选元素,使总数字和为j。

结合题目意思,我们需要在nums[0,n-1]区间挑选元素,使总数字和为所有元素数字和的一半。

所以我们可以用aim表示所有元素数字和的一半,

因此需要返回dp[n-1][aim];

代码实现

 
class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int n = nums.size(), sum = 0;
        for (auto x : nums)
            sum += x;
        if (sum % 2)
            return false; // 如果不能平分,直接返回 false
        int aim = sum / 2;
        vector<vector<bool>> dp(n, vector<bool>(aim + 1));
        for (int j = 0; j < n; j++)
            if(nums[0] == j || j==0) dp[0][j] = true;
        for (int i = 1; i < n; i++)
            for (int j = 0; j <= aim; j++) {
                dp[i][j] = dp[i - 1][j];
                if (j > nums[i])
                    dp[i][j] = dp[i][j] || dp[i - 1][j - nums[i]];
                else if (j == nums[i])
                    dp[i][j] = true;
            }
        return dp[n - 1][aim];
    }
};

494. 目标和 - 力扣(LeetCode)

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

题目解析

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

状态表示

01背包问题本质是从一些物品中选物品,本质上是有关组合的问题,而本题目也是在一些数中挑选出一些数,因为我们可以以01背包为模版,定义状态表示。

01背包问题的状态表示为,

定义dp[i][j]表示从前i个物品中挑选,总体积不超过j,所有选法中,所能达到的最大价值。

定义dp[i][j]表示从前i个物品中挑选,总体积为j,所有选法中,所能达到的最大价值。

因此我们可以定义dp[i][j]表示从nums[0,i]区间中挑选元素,使总数字和为j,一共有多少种选法。

状态转移方程

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

状态转移方程的推导是以最后一个位置的状况进行分类讨论。

dp[i][j]表示从nums[0,i]区间中挑选元素,使总数字和为j,一共有多少种选法。

  1. 如果挑选i位置的元素,

    1. 如果j-nums[i]<0, 此时表示i位置元素比j还要大,此时dp[i][j]=0;

    2. 如果j-nums[i] =0, 此时表示挑选i位置元素后,数字和就为j了,此时还需要考虑数字和为0的挑选种类次数,所以此时dp[i][j]=dp[i-1][j-nums[i-1]];

    3. 如果j-nums[i]>0, dp[i-1][j-nums[i]]表示从nums[0,i-1]区间中挑选元素,使总数字和为j-nums[i],一共有多少种选法。这些选法的每一种选法中,都加上i位置的元素,选法数不变,但是这些选法使得数字和都为j。 此时dp[i][j]=dp[i-1][j-nums[i]];

  2. 如果不挑选i位置的元素, 此时dp[i][j]=dp[i-1][j];

将上述情况进行合并和简化,得到状态转移方程,

 
                dp[i][j] = dp[i - 1][j];
                if (j >= nums[i])
                    dp[i][j] += dp[i - 1][j - nums[i]];
            

初始化

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

根据状态转移方程,我们知道,在推导(i,j)位置的状态时,需要用到(i-1,j)(i-1,j-nums[i])位置的状态,而只有j>nums[i]的时候才会用到(i-1,j-nums[i])位置的状态,所以我们只需要考虑(i-1,j)。

所以我们需要初始化第一行位置的状态,在推导蓝色部分位置状态的时候没有前驱,所以需要初始化这些位置的状态值。

我们可以添加虚拟节点,即多添加一行和一列,使这些虚拟节点成为蓝色位置的前驱,这样就不用初始化蓝色位置的值,而变为初始化虚拟节点即可。

这样做的好处是,虚拟结点的初始化可能比蓝色部分位置状态的初始化要简便许多。

【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析,动态规划,动态规划,算法,c++,开发语言

添加虚拟结点后,状态表示和状态转移方程会发生改变,即,

dp[i][j]表示从nums[0,i-1]区间中挑选元素,使总数字和为j,一共有多少种选法。

 
                dp[i][j] = dp[i - 1][j];
                if (j >= nums[i - 1])
                    dp[i][j] += dp[i - 1][j - nums[i - 1]];

添加虚拟节点后,有两点注意事项,

  1. 初始化虚拟节点,必须保证推导后续位置的状态的正确性。

  2. 下标的映射关系。

初始化虚拟节点:

我们根据状态表示,dp[i][j]表示从nums[0,i-1]区间中挑选元素,使总数字和为j,一共有多少种选法。我们同时可以根据状态表示赋予第一行意义,表示不选元素时的情况。

接下来初始化绿色位置的状态。

此时表示不选择元素,此时(0,0)位置dp[0][0]=1,其他位置为0。

下标映射关系:

  1. 此时,dp[i][j]表示从nums[0,i-1]区间中挑选元素,使总数字和为j,一共有多少种选法。 dp中i对应nums的i-1。

  2. 如果在nums前面添加一个占位符,就可以使得dp中i,j继续映射nums1,nums2中i,j。

我们这里选择第一种解决办法。

得到初始化,

 
        dp[0][0] = 1;  

填表顺序

根据状态转移方程,我们知道,在推导(i,j)位置的状态时,需要用到(i-1,j)(i-1,j-nums[i])位置的状态。使用(i-1,j-nums[i])状态时,j-nums[i]一定不会越界。所以只需要考虑(i-1,j)

  1. 固定i改变j, i的变化,需要从小到大,j的变化可以从小到大也可以从大到小。

  2. 固定j改变i, j的变化可以从小到大也可以从大到小,i的变化需要从小到大。

返回值

dp[i][j]表示从nums[0,i-1]区间中挑选元素,使总数字和为j,一共有多少种选法。

结合题目意思,我们需要在nums[0,n-1]区间挑选元素,使总数字和为所有元素数字和的一半。

所以我们可以用aim表示所有元素数字和的一半,

因此需要返回dp[n][aim];

代码实现

 
class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = 0;
        for (auto x : nums)
            sum += x;
        int aim = (sum + target) / 2;

        if (aim < 0 || (sum + target) % 2)
            return 0;
        int n = nums.size();
        vector<vector<int>> dp(n + 1, vector<int>(aim + 1)); // 建表
        dp[0][0] = 1;                                        // 初始化
        for (int i = 1; i <= n; i++)                         // 填表
            for (int j = 0; j <= aim; j++) {
                dp[i][j] = dp[i - 1][j];
                if (j >= nums[i - 1])
                    dp[i][j] += dp[i - 1][j - nums[i - 1]];
            }
        // 返回结果
        return dp[n][aim];
    }
};

结尾

今天我们学习了动态规划的思想,动态规划思想和数学归纳法思想有一些类似,动态规划在模拟数学归纳法的过程,已知一个最简单的基础解,通过得到前项与后项的推导关系,由这个最简单的基础解,我们可以一步一步推导出我们希望得到的那个解,把我们得到的解依次存放在dp数组中,dp数组中对应的状态,就像是数列里面的每一项。最后感谢您阅读我的文章,对于动态规划系列,我会一直更新,如果您觉得内容有帮助,可以点赞加关注,以快速阅读最新文章。

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!文章来源地址https://www.toymoban.com/news/detail-779096.html

到了这里,关于【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 从01背包开始动态规划:暴力解法 + dp + 滚动数组 + dp优化

        01背包问题是动态规划中最经典的问题之一,本篇将通过给出其四种解法,使读者更深刻理解动态规划。   有N件物品和一个容量是 V 的背包,每个物品有各自的体积和价值,且每个物品只能放一次(这也是01背包名字的由来),如何让背包里装入的物品具有最大的价值总

    2024年04月17日
    浏览(54)
  • 动态规划(DP)---- 01背包入门详解----二维图是学会的关键

        动态规划,Dynamic Programing(简称DP),个人认为是一种 算法思想 , 用来解决多阶段多层次的选择问题,把一个复杂的问题分解成每个小块的子问题然后一个个解决来找到最优解。     DP适用 重叠子问题 和 最优子结构的性质 的问题。     DP问题范围分为 线性与非线性

    2024年02月03日
    浏览(39)
  • 算法训练第四十二天|01背包问题 二维 、01背包问题 一维、416. 分割等和子集

    视频链接:https://www.bilibili.com/video/BV1cg411g7Y6/ 参考:https://programmercarl.com/%E8%83%8C%E5%8C%85%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%8001%E8%83%8C%E5%8C%85-1.html 对于面试的话,其实掌握01背包,和完全背包,就够用了,最多可以再来一个多重背包。 而完全背包又是也是01背包稍作变化而来,即:完全

    2024年02月01日
    浏览(46)
  • 【LeetCode动态规划#06】分割等和子集(01背包问题一维写法实战)

    分割等和子集 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 示例 1: 输入:nums = [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11] 示例 2: 输入:nums = [1,2,3,5] 输出:false 解释:数组不能分割

    2023年04月09日
    浏览(67)
  • 01背包问题-递推公式的自我理解与LeetCode 416. 分割等和子集

    学算法好痛苦,完全是对我智力的一次次折磨,看了好多博客,对二维dp数组的理解都是直接搬了代码随想录,搬了随想录又没详细解释,大家都是一眼看懂的吗,好吧() 如果有一个容量为 j 的这样的背包——一个独立的,容量为j的背包。(没把它理解为“剩余容量”) 对于

    2024年02月07日
    浏览(44)
  • 力扣算法刷题Day42|动态规划:01背包问题 分割等和子集

    力扣题目:01背包问题(二维数组) 刷题时长:参考题解 解题方法:动态规划 + 二维dp数组 复杂度分析 时间 空间 问题总结 理解递推公式困难 本题收获 动规思路:两层for循环,第一层i遍历物品,第二层j枚举背包容量以内所有值 确定dp数组及下标的含义:dp[i][j] 表示从下标

    2024年02月13日
    浏览(62)
  • 【力扣】416. 分割等和子集 <动态规划、回溯>

    给你一个 只包含正整数的非空数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 示例 1: 输入:nums = [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11] 。 示例 2: 输入:nums = [1,2,3,5] 输出:false 解释:数组不能分割成两个元素和

    2024年02月10日
    浏览(39)
  • leetcode416. 分割等和子集(动态规划-java)

    来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/partition-equal-subset-sum 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 示例 1: 输入:nums = [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11] 。

    2024年02月11日
    浏览(37)
  • 力扣hot100:416.分割等和子集(组合/动态规划/STL问题)

    组合数问题 我们思考一下,如果要把数组分割成两个子集,并且两个子集的元素和相等,是否等价于在数组中寻找若干个数使之和等于所有数的一半?是的! 因此我们可以想到,两种方式: ①回溯的方式找到target,但是回溯是阶乘级别的算法,这里会超时。 ②从前往后遍历

    2024年04月28日
    浏览(37)
  • 动态规划(DP)---背包二维图

    状态方程:dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - w[i]] + v[i]) 应该是看完我写的DP文章来的吧,如果没有看到,希望看看DP那个文章结合这个理解,DP那个文章内部写了我对于01背包类型的想法与思路,有时间的网友可以了解hhh。 分析这个东东的时候,其实是四个方向嘛,我推荐要是

    2024年02月03日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包