【进击的算法】动态规划——不同维度的背包问题

文章目录

  • 前言
  • 动态规划的维度
  • 二维动规
    • leetcode416、分割等和子集
    • leetcode1049. 最后一块石头的重量 II
    • leetcode494、目标和
  • 三维动规
    • leetcode474. 一和零
  • 结语

前言

大家好久不见,这次我们一起来学习一下动态规划中怎么确定维度,和对应问题如何解决。

动态规划的维度

一个维度:只有物品
两个维度:物品和容量
三个维度:物品和容量1和容量2

之前讲解动态规划问题时,斐波那契数列就是一个很简单的一维动态规划问题,因为我们要考虑的状态只有这个数的值,(一维动态规划),之后讲解了01背包问题,也就是有了第二个维度,不仅要考虑物品,还要考虑背包容量(二维动态规划)

其实在这里一定要明确好状态到底是什么,在我看来:与要求结果相关的状态,都是可以列为维度的,我们是将物品范围和背包容量都列为了状态因为他们都会影响结果


二维动规

leetcode416、分割等和子集

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

  • 示例 1:
    输入:nums = [1,5,11,5]
    输出:true
    解释:数组可以分割成 [1, 5, 5] 和 [11] 。
  • 示例 2:
    输入:nums = [1,2,3,5]
    输出:false
    解释:数组不能分割成两个元素和相等的子集。

这个问题要我们寻找等和的子集,我们可以把nums数组里的元素抽象为背包问题里的石头,把分成的两个等和子集抽象为背包。

  • dp[i][j] 表示前i个元素放到容量为j的背包的最大重量

  • dp[i][j] = max(dp[i-1][j],dp[i-1][j-nums[i]]+nums[i])

就算压缩为一维动态规划,那也是压缩的空间而已,本质上我们还是定义了两个状态!

#define MAX(a,b) ((a)>(b)?(a):(b))

bool canPartition(int* nums, int numsSize){
   
    int sum = 0;
    for(int i = 0;i<numsSize;i++)
    {
   
        sum+=nums[i];
    }
    if(sum%2 != 0) return false;
    int target = sum / 2;
    
    int* dp = (int*)calloc(sizeof(int),target+1);

    //先遍历物品,再遍历列!
    for(int i = 0;i<numsSize;i++)
    {
   

你可能感兴趣的:(算法,动态规划,数据结构)