首页 > 其他分享 >零一背包

零一背包

时间:2025-01-15 14:56:40浏览次数:1  
标签:零一 背包 nums int sum vector fan2 dp

[Algo] 零一背包

1. 夏季特惠

// 1. 夏季特惠
// https://leetcode.cn/problems/tJau2o/description/
long maxHappyValue(vector<long> &a, vector<long> &b, vector<long> &w, long x)
{
    // a: 原价数组, b: 现价数组, w: 快乐值数组, x: 预算
    long n = a.size();
    vector<long> diff(n);
    for (long i = 0; i < n; i++) diff[i] = a[i] - 2 * b[i];
    // diff[i] >= 0: 直接购买(提高预算), diff[i] < 0: 01背包
    long ans = 0;
    vector<long> val, cost;
    for (long i = 0; i < n; i++)
    {
        if (diff[i] >= 0) 
        {
            ans += w[i];
            x += diff[i];
        }
        else
        {
            val.push_back(w[i]);
            cost.push_back(-1 * diff[i]);
        }
    }

    long m = val.size();
    vector<vector<long>> dp(m + 1, vector<long>(x + 1)); // dp[i][j]: 用前i个物品容量不超过j获得的最大价值
    for (long i = 1; i <= m; i++)
    for (long j = 0; j <= x; j++)
    {
        long p1 = dp[i - 1][j], p2 = 0;
        if (j >= cost[i - 1]) p2 = val[i - 1] + dp[i - 1][j - cost[i - 1]];
        dp[i][j] = max(p1, p2);
    }
    ans += dp[m][x];
    return ans;
}

2. 目标和

// 2. 目标和
// https://leetcode.cn/problems/target-sum/
int findTargetSumWays(vector<int>& nums, int target) {
    // 原问题等价于将nums分为两个子集A和B, 使得sum(A) - sum(B) = target
    // 由于sum(A) + sum(B) = sum(nums), 可得sum(A) = (target + sum(nums)) / 2
    // 问题转化为01背包问题: 从nums中选取若干个数, 使得其和等于(target + sum(nums)) / 2的方案数
    int sum = 0;
    for (int num : nums) sum += num;
    if (sum < target || (sum + target) % 2 == 1) return 0;
    int n = nums.size(), m = (sum + target) / 2;
    if (m < 0) return 0;

    vector<vector<int>> dp(n + 1, vector<int>(m + 1)); // dp[i][j]: 前i个数和为j的方案数
    dp[0][0] = 1;
    for (int i = 1; i <= n; i++)
    for (int j = 0; j <= m; 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][m];
}

3. 最后一块石头的重量

// 3. 最后一块石头的重量
// https://leetcode.cn/problems/last-stone-weight-ii/description/
int lastStoneWeightII(vector<int>& stones) {
    // 原问题等价于将stones分为两个子集A和B, 使得|sum(A) - sum(B)|最小
    // 问题转化为01背包问题: 从stones中选取若干个数, 使得其和尽可能接近但不超过sum(stones) / 2
    int sum = 0;
    for (int stone : stones) sum += stone;
    int n = stones.size(), m = sum / 2;
    vector<vector<int>> dp(n + 1, vector<int>(m + 1)); // dp[i][j]: 前i个数中累加和尽可能接近但不超过j的累加和
    // dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - stones[i - 1]] + stones[i - 1])
    for (int i = 1; i <= n; i++)
    for (int j = 0; j <= m; j++)
    {
        dp[i][j] = dp[i - 1][j];
        if (stones[i - 1] <= j) dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - stones[i - 1]] + stones[i - 1]);
    }
    return sum - 2 * dp[n][m];
}

4. 购物单(有依赖的背包问题)

// 4. 购物单(有依赖的背包问题)
// https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4
int maxContentValue(int n, int m, vector<int> &v, vector<int> &w, vector<int> &q) {
    // n: 预算, m: 物品数量, v: 价格, w: 重要度, q: 主商品编号
    // 根据主商品进行动态规划
    vector<vector<int>> dp(m + 1, vector<int>(n + 1)); // dp[i][j]: 0...i物品, 预算不超过j的总价值
    vector<bool> isMain(m + 1, false); // 是否为主商品
    vector<vector<int>> sub(m + 1, vector<int>(0)); // 子商品列表
    for (int i = 1; i <= m; i++)
    {
        w[i] = w[i] * v[i]; // 重要度转化为价值
        if (q[i] == 0) isMain[i] = true;
        else sub[q[i]].push_back(i);
    }

    int pre = 0; // 前一个主商品
    for (int i = 1; i <= m; i++)
    {
        if (!isMain[i]) continue;
        for (int j = 0; j <= n; j++)
        {
            dp[i][j] = dp[pre][j]; // 可能性1: 不选当前主商品
            if (j >= v[i]) dp[i][j] = max(dp[i][j], dp[pre][j - v[i]] + w[i]); // 可能性2: 选当前主商品
            int fan1 = sub[i].size() >= 1 ? sub[i][0] : -1;
            int fan2 = sub[i].size() >= 2 ? sub[i][1] : -1;
            if (fan1 != -1 && j >= v[i] + v[fan1]) 
            dp[i][j] = max(dp[i][j], dp[pre][j - v[i] - v[fan1]] + w[i] + w[fan1]); // 可能性3: 选当前主商品和第一个子商品
            if (fan2 != -1 && j >= v[i] + v[fan2]) 
            dp[i][j] = max(dp[i][j], dp[pre][j - v[i] - v[fan2]] + w[i] + w[fan2]); // 可能性4: 选当前主商品和第二个子商品
            if (fan1 != -1 && fan2 != -1 && j >= v[i] + v[fan1] + v[fan2]) 
            dp[i][j] = max(dp[i][j], dp[pre][j - v[i] - v[fan1] - v[fan2]] + w[i] + w[fan1] + w[fan2]); // 可能性5: 选当前主商品和两个子商品
        }
        pre = i;
    }
    return dp[pre][n];
}

标签:零一,背包,nums,int,sum,vector,fan2,dp
From: https://www.cnblogs.com/yaoguyuan/p/18673009

相关文章

  • 代码随想录Day35 | 01背包问题 二维,01背包问题 一维,416.分割等和子集
    代码随想录Day35|01背包问题二维,01背包问题一维,416.分割等和子集01背包问题二维动态规划经典问题dp定义:dp[i][j]表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+va......
  • 力扣leetcode 416.分割等和子集 动态规划 0-1背包
    题目:给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。示例1:输入:nums=[1,5,11,5]输出:true解释:数组可以分割成[1,5,5]和[11]。示例2:输入:nums=[1,2,3,5]输出:false解释:数组不能分割成......
  • 背包九讲练习题
    01背包有N种物品和一个容量为V的背包,每种物品只有1个,第i种物品的体积为v[i],价值为w[i]。问将哪些物品装入背包,可使总体积不超过背包容量,且总价值最大,输出最大值。0<N,V<=1000;0<v[i],w[i]<=1000#include<bits/stdc++.h>intmain(){intN,V;std::cin>>N>>V;......
  • 01背包【模板】
    https://www.luogu.com.cn/problem/P2871#include<bits/stdc++.h>#definelcp<<1#definercp<<1|1#defineINF2e9usingnamespacestd;#defineendl'\n'usingll=longlong;usingpii=pair<ll,ll>;constdoublePI=a......
  • 分组背包+四位
    https://ac.nowcoder.com/acm/contest/99784/E#include<bits/stdc++.h>#definelcp<<1#definercp<<1|1#defineINF2e9usingnamespacestd;#defineendl'\n'usingll=longlong;usingpii=pair<ll,ll>;constdoubleP......
  • 代码随想录训练营第三十七天| 完全背包 518. 零钱兑换 II 377. 组合总和 Ⅳ 70. 爬楼
    完全背包理论直接的说明就是把01背包的有限次选取变为无限次选取求最大价值相对的遍历方向也可以相互调换因为dp[j]只需要上次的计算结果就行 publicclassCarlcodeAllBag{publicstaticvoidtestCompletePack(){//先遍历物品再遍历背包int[]......
  • 01背包问题 Golang实现
    背包问题的分类:01背包描述:有n件物品和一个最多能背重量为w的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。思路分析:问题核心:从给定的......
  • 25年开篇之作---动态规划系列<七> 01背包问题
    目录一:背包问题的简介二:01背包问题1.模板题2.LeetCode经典例题一:背包问题的简介背包问题(Knapsackproblem)是⼀种组合优化的NP完全问题。问题可以描述为:给定⼀组物品,每种物品都有⾃⼰的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最⾼。......
  • 动态规划<八> 完全背包问题及其余背包问题
    目录例题引入---找到解决问题模版LeetCode经典OJ题1.第一题 2.第二题 3.第三题 其余的一些背包问题1.二维费用的背包问题1.第一题2.第二题2.其余杂题例题引入---找到解决问题模版OJ传送门牛客DP42【模板】完全背包画图分析: 使用动态规划解决(第二问与......
  • 完全背包问题
    一、问题描述完全背包问题是一个经典的动态规划问题。其问题描述如下:二、算法思路定义状态我们使用动态规划来解决这个问题。定义一个一维数组dp,其中dp[j]表示背包容量为j时能获得的最大价值。状态转移方程对于每种物品i,我们有两种选择:放或者不放。由于每种物品有无限......