代码随想录算法训练营第41天|卡码网 46. 携带研究材料、Leetcode 416. 分割等和子集

卡码网 46. 携带研究材料

题目链接:卡码网 46. 携带研究材料
题目描述: 小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。他需要带一些研究材料,但是他的行李箱空间有限。这些研究材料包括实验设备、文献资料和实验样本等等,它们各自占据不同的空间,并且具有不同的价值。
小明的行李空间为 N,问小明应该如何抉择,才能携带最大价值的研究材料,每种研究材料只能选择一次,并且只有选与不选两种选择,不能进行切割。
输入描述:
第一行包含两个正整数,第一个整数 M 代表研究材料的种类,第二个正整数 N,代表小明的行李空间。

第二行包含 M 个正整数,代表每种研究材料的所占空间。

第三行包含 M 个正整数,代表每种研究材料的价值。
输出描述: 输出一个整数,代表小明能够携带的研究材料的最大价值。
思路: 本题不同与以往的Leetcode题目,需要额外处理输入输出,不过本题是一道01背包模板题,还是比较简单的。(不了解01背包可以先看下面两个链接,着重注意优化前后的遍历顺序
01背包理论基础
01背包理论基础(利用滚动数组优化)
代码如下:(动态规划)

#include <iostream>
#include <algorithm>
 
using namespace std;
 
const int N = 5010;
 
int v[N],w[N],f[N][N];
 
int main()
{
    int n,m;
    cin >> n >> m;
    for(int i = 1; i <= n; i ++) cin >> v[i];
    for(int i = 1; i <= n; i ++) cin >> w[i];
     
    for(int i = 1; i <= n; i ++ )
        for(int j = 0; j <= m; j ++ )
        {
            if(j >= v[i]) f[i][j] = max(f[i - 1][j] , f[i - 1][j - v[i]] + w[i]);
            else f[i][j] = f[i - 1][j];
        }
    cout << f[n][m];
    return 0;
}

代码如下:(动态规划+滚动数组优化)

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 5010;

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

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

Leetcode 416. 分割等和子集

题目链接:Leetcode 416. 分割等和子集
题目描述: 给你一个只包含正整数的非空数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
思路: 本题可以用01背包解决,不过难点在于如何将本题转换成01背包问题。

  • 题中需要让子集元素之和等于target / 2 ,因此可以将其看为背包容量。
  • 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
  • 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
  • 背包中每一个元素是不可重复放入。

代码如下:

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        vector<int> dp(10005, 0);
        //计算数组元素总和的一半
        int sum = accumulate(nums.begin(), nums.end(), 0);
        if (sum & 1) //如果sum是奇数直接返回false
            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;
    }
};
  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度: O ( n ) O(n) O(n)

总结: 01背包问题算是背包问题中的基础问题,理解其原理之后会对后续更复杂的背包问题更有帮助。

最后,如果文章有错误,请在评论区或私信指出,让我们共同进步!

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值