代码随想录算法训练营第41天|背包理论基础 滚动数组法 416.分割等和子集

背包理论基础

        终于开始刷大名鼎鼎的背包问题了,背包问题有点复杂,我还是懂了但没完全懂,下面是我现在的理解,我们把dp[i][j]定义为i个物品在背包容量为j下的价值,那么这样就转换为如果要求价值,这个价值和前一个物品有关,假如说现在的物品没有添加到背包里面,那么dp[i][j]=dp[i-1][j],因为没有添加,所以价值的不便的,但是假如说现在的物品添加到背包里面了,那么dp[i][j]=dp[i-1][j-weight[i]]+value[i],因为假如说添加了 ,那么肯定得留有weight[i]的容量才能让这个物品放下去,所以这时候前面的物品的背包容量应该是j-weight[i],那么在前面的基础上,就需要加上这个物品的价值,才是现在加入这个物品后的价值。

https://kamacoder.com/problempage.php?pid=1046

#include<iostream>
using namespace std;
#include<vector>
int n,bagweight;
void solve()
{
    vector<int>weight(n,0);
    vector<int>value(n,0);
    vector<vector<int>>dp(n,vector<int>(bagweight+1,0));
    for(int i=0;i<n;i++)
    {
        cin>>weight[i];
    }
    for(int j=0;j<n;j++)
    {
        cin>>value[j];
    }
    for(int j=weight[0];j<=bagweight;j++)
    {
        dp[0][j]=value[0];
    }
    for(int i=1;i<n;i++)
    {
        for(int j=1;j<=bagweight;j++)
        {
            if(weight[i]>j)
            {
                dp[i][j]=dp[i-1][j];
            }
            else
            {
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
            }
        }
    }
    cout<<dp[n-1][bagweight]<<endl;
}
int main()
{
    while(cin>>n>>bagweight)
    {
        solve();
    }
    return 0;
}

滚动数组法

        滚动数组法就是把二维数组转换为一维数组,根据上面的讲解可以知道dp[i][j]其实只是跟dp[i-1][x](这里的x可能是j也可能是j-weight[i]),所以一维数组法就相当于每次在计算新的一行的时候,把上一行的结果搬到这一行,然后这一行再从后面向前面遍历更新值,为什么是从后往前遍历呢,因为dp[i][j]是跟之前的数值有关,假如说从前往后遍历,那么前面的值更新了,会导致后面的值在计算的时候用的dp[i-1][j]并不是原先的值(因为在前面遍历的时候前面的数值已经改变了,不再是我们直接搬下来的那些值)。

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    int n,bagweight;
    cin>>n>>bagweight;
    vector<int>dp(bagweight+1,0);
    vector<int>weight(n,0);
    vector<int>value(n,0);
    for(int i=0;i<n;i++)
    {
        cin>>weight[i];
    }
    for(int i=0;i<n;i++)
    {
        cin>>value[i];
    }
    for(int i=0;i<n;i++)
    {
        for(int j=bagweight;j>=weight[i];j--)
        {
            dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
        }
    }
    cout<<dp[bagweight]<<endl;
    return 0;
}

416.分割等和子集

https://leetcode.cn/problems/partition-equal-subset-sum/

        这道题神奇的点在于它居然也是动态规划的,我们把背包的容量看成是数的总和除以2,物品的价值看成是数的大小,问题就转化为了求背包容量为数的总和除以2的情况下,是否能够使得物品的最大价值等于数的总和除以2。

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum=0;
        vector<int>dp(10001,0);
        for(int i=0;i<nums.size();i++)
        {sum+=nums[i];}
        if(sum%2==1) return false;
        int target=sum/2;
        for(int i=0;i<nums.size();i++)
        {
            for(int j=target;j>=nums[i];j--)
            {
                dp[j]=max(dp[j],dp[j-nums[i]]+nums[i]);
            }
        }
        if(dp[target]==target)
        return true;
        return false;
    }
};

最近更新

  1. TCP协议是安全的吗?

    2024-03-11 18:06:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-11 18:06:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-11 18:06:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-11 18:06:03       18 阅读

热门阅读

  1. python协程理解笔记,

    2024-03-11 18:06:03       20 阅读
  2. 递归在解决链表问题中的应用

    2024-03-11 18:06:03       19 阅读
  3. 前端环境配置Nodejs,NRM,YARN

    2024-03-11 18:06:03       20 阅读
  4. vue,elementUI多表单同时提交,表单校验解决方案

    2024-03-11 18:06:03       21 阅读
  5. 高级优化理论与方法(三)

    2024-03-11 18:06:03       17 阅读
  6. List数据去重的4种有效方法

    2024-03-11 18:06:03       24 阅读
  7. linux服务器升级tomcat步骤

    2024-03-11 18:06:03       20 阅读