首页 > 其他分享 >【DP解密多重背包问题】:优化策略与实现

【DP解密多重背包问题】:优化策略与实现

时间:2024-09-28 23:47:52浏览次数:11  
标签:多重 背包 int 解密 问题 DP 物品 dp

文章目录

在这里插入图片描述

什么是多重背包问题?

多重背包问题是一个经典的组合优化问题。与标准背包问题不同,在多重背包问题中,每种物品可以选择多个,而不是只选择一次。具体来说,给定一个背包的容量和若干种物品,每种物品有一个重量和价值,目标是最大化在背包中放入的物品总价值,同时不超过背包的容量。

在解决这个问题时,通常使用动态规划或贪心算法,具体取决于问题的约束条件。
在日常生活中,我们常常面临选择的困扰,如何在有限的资源下最大化收益?多重背包问题正是这种选择的数学模型。具体而言,给定一个背包的容量 C C C 和 n n n 种物品,每种物品 i i i 具有重量 w w w 和价值 v v v,而且可以选择多个单位。我们的目标是最大化总价值,同时不超过背包的容量。

多重背包问题的数学模型

我们可以通过以下公式来表示多重背包问题:

max ⁡ ∑ i = 1 n v i ⋅ x i \max \sum_{i=1}^{n} v_i \cdot x_i maxi=1∑n​vi​⋅xi​

其中, x i x_i xi​ 表示选择物品 i i i 的数量,满足以下约束条件:

∑ i = 1 n w i ⋅ x i ≤ C \sum_{i=1}^{n} w_i \cdot x_i \leq C i=1∑n​wi​⋅xi​≤C

x i ∈ Z ≥ 0 x_i \in \mathbb{Z}_{\geq 0} xi​∈Z≥0​

接下来会展示几道例题。

例题

多重背包问题Ⅰ

问题:

在这里插入图片描述

输出格式和数据范围:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

算法原理:
相较于01背包问题来说,多重背包问题当中每个物品的个数不止是一个而是多个。相较于完全背包问题来说这些物品都不是无锡无限的。
举个例子:

物品标号1234
单个物品容量1234
物品个数3132
单个物品价值2445

以上面这个为例子,假设背包的容量是5,可以选择的物品个数是4,我们该如何选择呢,按照01背包问题的思想:我们可以先创建一个dp数组,dp[i]表示物品容量是i时的最大价值。
在 0-1 背包问题中,每个物品只能选择一次,因此状态转移方程是:

d p [ j ] = m a x ( d p [ j ] , d p [ j − v [ i ] ] + w [ i ] ) dp[j] = max(dp[j], dp[j - v[i]] + w[i]) dp[j]=max(dp[j],dp[j−v[i]]+w[i])

其中, d p [ j ] dp[j] dp[j]表示容量为 j j j时的最大价值。

在多重背包问题中,每个物品有多个数量可以选择,因此状态转移方程变为:

d p [ j ] = m a x ( d p [ j ] , d p [ j − v [ i ] ] + w [ i ] , d p [ j − 2 v [ i ] ] + 2 w [ i ] , … , d p [ j − n v [ i ] ] + n w [ i ] ) dp[j] = max(dp[j], dp[j - v[i]] + w[i], dp[j - 2v[i]] + 2w[i], \dots, dp[j - nv[i]] + nw[i]) dp[j]=max(dp[j],dp[j−v[i]]+w[i],dp[j−2v[i]]+2w[i],…,dp[j−nv[i]]+nw[i])

这个公式的解释是,针对每个容量 j j j,我们考虑物品 i i i 的不同数量,找到一个最优的数量组合,使得价值最大化。

解释:

  1. 当选择 0 个物品 i i i 时,价值为 d p [ j ] dp[j] dp[j]。
  2. 当选择 1 个物品 i i i 时,价值为 d p [ j − v [ i ] ] + w [ i ] dp[j - v[i]] + w[i] dp[j−v[i]]+w[i]。
  3. 当选择 2 个物品 i i i时,价值为 d p [ j − 2 v [ i ] ] + 2 w [ i ] dp[j - 2v[i]] + 2w[i] dp[j−2v[i]]+2w[i]。
  4. 依此类推,直到选择最多 n n n个物品 i i i。

因此,针对每个容量 ( j ),我们计算每种数量下的最大值,并更新 d p [ j ] dp[j] dp[j]。

所以我们需要一个循环来遍历每一种个数的情况:
在这里插入图片描述

代码展示:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main()
{
    int N,V;
    cin>>N>>V;
    vector<int> dp(V+1,0);
    for(int i=0;i<N;i++)
    {
        int vi,wi,si;
        cin>>vi>>wi>>si;
        for(int j=V;j>=vi;j--)
        {
            for(int k=1;k<=si&&j>=k*vi;k++)
            {
                dp[j]=max(dp[j],dp[j-k*vi]+k*wi);
            }
        }
    }
    cout<<dp[V]<<endl;
    return 0;
}

多重背包问题Ⅱ

问题:

在这里插入图片描述

数据范围:

在这里插入图片描述

输入样例和输出样例:

在这里插入图片描述

可以看见这道题的题目要求和上道题一模一样,但是数据范围发生了变化,我们先看看上道题的数据范围是100,100,100。套了三层循环顶多也就100万,对于C++来说100万是可以接受的,但是这道题的数据范围是1000,2000,2000,算出来是 4 ∗ 1 0 9 4*10^9 4∗109,用刚才那种算法是会超时的。

算法优化:
假如某个物品有7个,我们是不是可以将这7个物品分为若干份,最容易想到的:
七个物品我们可以分为7份,然后每个物品的物品数量也可以相应的划分,是不是可以转换为一个01背包问题,但是这里我们划分的份数是不是太多了,我们可以来简化一下,我是否可以将一个物品的数量划分为2的幂次方个之和,就拿上面的例子为例,7个物品,我们可以划分为:1+2+4,这里很巧合的是刚刚好划分完了,但是如果我们有8个物品呢?是不是最后还剩下一一个,这个不能划分为2的幂次方的我们单独讨论即可,我们将每个物品分好组之后然后进行一次01背包问题即可。
在处理多重背包问题时,我们可以使用二进制拆分的方法来简化问题。

原因与解释:

  1. 二进制拆分

    • 每个物品的数量可以被表示为一系列 2 的幂次方之和。这是因为任何正整数都可以通过二进制表示来拆分成若干个 1、2、4、8 等的组合。例如,数字 7 可以拆分为 (1 + 2 + 4)。
    • 对于 8 这个例子,你可以将其拆分为 (8) 或者 (4 + 4)(视情况而定)。这个方法将减少需要考虑的物品种类,使得后续的背包问题更容易处理。
  2. 减少物品种类

    • 通过将物品的数量拆分为 2 的幂次方,我们实际上减少了在解决背包问题时所需考虑的物品数量。例如,7 个物品可以看作 1 个物品(1 个)、1 个物品(2 个)和 1 个物品(4 个),而不是直接处理 7 个物品。
    • 这使得问题转变为多个 0-1 背包问题,每个物品的“虚拟”数量在其对应的 0-1 背包问题中被考虑。
  3. 独立处理剩余物品

    • 如果在拆分后有剩余的物品(例如在处理 8 个物品时多出 1 个),可以单独将这一部分作为一个新的物品进行处理。这不会影响已经拆分的部分,因为已经处理的组合都是由 2 的幂构成的。

总结:
通过将物品数量拆分为 2 的幂次方之和,你可以有效地将多重背包问题转换为多个 0-1 背包问题,简化问题的复杂性,并且只需关注相对较少的物品组合。这个策略的有效性源于数学上对整数的分解性质,确保了每个可能的选择都能够被覆盖。

代码展示:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

//大数据范围用二进制分解优化

const int V=2001;
int n,m;

struct Good
{
    //容量
    int v;
    //价值
    int w;
};

int main()
{
    vector<Good> good;
    vector<int> dp(V,0);
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        int vi,wi,si;
        cin>>vi>>wi>>si;
        for(int k=1;k<=si;k*=2)
        {
            si-=k;
            good.push_back({k*vi,k*wi});
        }
        //有剩的,但是不能组成2的幂次方
        if(si>0)
            good.push_back({si*vi,si*wi});
    }
    //重新做一次01背包
    for(auto e:good)
    {
        for(int j=m;j>=e.v;j--)
        {
            dp[j]=max(dp[j],dp[j-e.v]+e.w);
        }
    }
    cout<<dp[m]<<endl;
    return 0;
}

总结

在本文中,我们深入探讨了多重背包问题的动态规划解法及其优化策略。通过将物品的数量拆分为 2 的幂次方之和,我们成功地将复杂的多重背包问题转换为多个简单的 0-1 背包问题,从而降低了计算复杂度,提高了算法的效率。此外,结合具体实例和详细的代码实现,使得这一理论变得更为实用。

多重背包问题不仅在计算机科学中有着重要的应用,还在现实生活中为资源分配、库存管理等问题提供了有效的解决方案。掌握这一算法思路,可以为解决更复杂的组合优化问题奠定基础。

希望通过本篇文章,读者能够更好地理解多重背包问题,并在实际编程中灵活运用这些优化策略。

标签:多重,背包,int,解密,问题,DP,物品,dp
From: https://blog.csdn.net/2301_79969994/article/details/142595986

相关文章

  • 动态规划(有背包问题)
    目录1.动态规划的介绍2.动态规划的例题第1道题数字三角形(如果想看递归写法可以到我的记忆化递归里去看看记忆化递归_将递归程序记忆化-CSDN博客)第2道题最长公共子序列(模板) 第3道题 最长上升子序列第4道题最大子段和背包系列问题01背包完全背包1.动态规划......
  • NOIP2024集训Day37 DP
    NOIP2024集训Day37DPA.[CQOI2011]放棋子设\(f_{i,j,k}\)表示前\(k\)种棋子放了任意\(i\)行、\(j\)列。决策是:在哪些位置填同种颜色的棋子。于是美剧上一个状态的\(i,j\)(表示为\(l,r\)),上一状态\(k_1=k-1\)。设\(g_{i,j,k}\)表示\(k\)个同种颜色的......
  • [题目记录]一本通高手训练-01背包
    题意有\(n\)个物品,每个物品体积为\(s_i\),价值为\(v_i\),求背包容量为\(1,2,\cdotsm\)时最大价值.\(n\le1e6,m\le1e5,s\le300,v\le1e9\)时空限制\(5s,512MB\)题解普通01背包复杂度\(O(nm)\),无法满足\(n\le1e6,m\le1e5\).发现\(s\le300\),可以考虑......
  • Profibus DP转Modbus RTU主站协议转换网关
    一,设备主要功能捷米特JM-RTU-DP网关实现ProfibusDP网络与ModbusRTU网络之间的数据通讯。即将ModbusRTU设备转换为ProfibusDP设备。应用广泛:捷米特JM-RTU-DP广泛应用于ModbusRTU接口的变频器、仪表、马保、上位机等等。在工业除尘自动化场景中,ProfibusDP从站转ModbusRT......
  • E60 树形DP+贪心 P3574 [POI2014] FAR-FarmCraft
    视频链接:   P3574[POI2014]FAR-FarmCraft-洛谷|计算机科学教育新生态(luogu.com.cn)//树形DP+贪心O(nlogn)#include<iostream>#include<cstring>#include<algorithm>usingnamespacestd;constintN=500005;inthead[N],to[N<<1],ne[N<......
  • Kubernetes 服务发现 监控Endpoints
    监控Pod之前的apiserver实际上就是一种特殊的Endpoints,现在我们同样来配置一个任务用来专门发现普通类型的Endpoint,其实就是Service关联的Pod列表,由于并不是所有的Endpoints都会提供metrics接口,所以需要我们主动告诉Prometheus去发现哪些Endpoints,当然告诉的方式有......
  • 双端之Nginx+Php结合PostgreSQL搭建Wordpress
    第一台虚拟机:安装Nginx更新系统包列表:sudoaptupdate安装Nginx及php扩展:sudoaptinstallnginxphp-fpmphp-pgsqlphp-mysqli-y启动Nginx服务:sudosystemctlstartnginx检查Nginx是否正常运行:xdg-openhttp://localhost注意:终端命令打开网址打......
  • LAMP+WordPress 部署与配置
    LAMP+WordPress部署与配置安装Apachesudodnfinstallhttpd启动Apache服务sudosystemctlenablehttpdsudosystemctlstarthttpd开放端口sudofirewall-cmd--permanent--add-service=httpsudofirewall-cmd--permanent--add-service=httpssudofirewall-cm......
  • 宝塔Nginx开启fastcgi_cache分别缓存WordPress移动和pc端
    FastCGI_cache是Nginx的缓存模块,能够从Nginx层面实现网页静态化,有效提高网站的并发能力、减少PHP运行时间和请求响应时间,大大提升页面加载速度。Fastcgi_cache能够直接在nginx层面提供缓存内容,而无需涉及PHP或WordPress,在没有第三方广告情况下加速效果很不错!网上不少此教程,但是没......
  • 三星G8 OLED显示器S34BG850SC,使用DP线连接电脑,显示器黑屏问题解决。
    这个问题在网上好像很多人问,但是每个人的情况不同,总之我也是遇到了。事情大概:PC机显卡的DP口通过显示器自带的MiniDP线和显示器相连,这个没什么好说的了,原配只送MiniDP线,想必买这台显示器的人都是先用的这根线。然而我有一台NUC,通过雷电口也连接到了这台显示器。所以我这台G8是......