【算法】DP背包问题(C/C++)

简介: 【算法】DP背包问题(C/C++)

背包问题是一类经典的DP类问题,通常一般会限定背包容量,物品的重量、价值。让你在有限的空间内选择的物品具有最大的价值。这一类的问题我们可以利用动态规划DP的思想进行解决,其效率也非常高。

动态规划(Dynamic Programming,简称DP)是一种通过把复杂的原问题分解为相对简单的子问题的方式,进而求解原问题的方法。背包问题(Knapsack Problem)是动态规划中的经典问题之一,它有多种变体,其中有01背包、多重背包、完全背包、混合背包、二位费用背包、分组背包、有依赖的背包、树形背包等变形问题。

为什么说动态规划DP是解决背包问题的好方法,关键在于背包问题在于将问题进行分解为子问题,背包问题可以将背包容量进行分解,以最少的容量去装纳价值最高的物品,每一步的最优解,也就是每一步所能拿的价值最大,必然导致了最终整个背包的价值最大,在遍历物品时,我们定义的dp[i][j]为在前i件物品中背包容量为j所选择最大化,当i的不断增大,前面的状态必然被遍历过,且已经被求出来,这样后面我们便可以减少遍历次数,拿过来直接用即可。

0-1背包问题

问题描述:给定一组物品,每个物品都有一个重量和一个价值,现有一个背包可以承载的最大重量为W。问可以选择哪些物品,使得在不超过背包容量的前提下,所携带物品的总价值最大。

状态定义:dp[i][j] 表示从前i个物品中选取一些放入容量为j的背包中,能够获得的最大价值。

状态转移方程: 如果不取第i个物品,则 dp[i][j] = dp[i-1][j],如果取第i个物品(前提是j >=

w[i]),则 dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])

综上,dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i] if j >= w[i])

初始化:dp[0][j] = 0,即没有物品时,任何容量的背包价值都为0。

遍历顺序:先遍历物品,再遍历背包容量。

#include<stdio.h>
int f[100][100];//f[i][j]为在前i件物品中背包容量为j所选择最大化
int w[100],v[100];//w:物品重量,v:物品价值
int max(int x,int y){
  return x>y?x:y;
}
int main(){
  int i,j,n,m;//n为最大物品数,m为最大背包容量
  scanf("%d%d",&n,&m);
  for(i=1;i<=n;i++){
    scanf("%d%d",&w[i],&v[i]);
  }
  for(i=1;i<=n;i++){//i物品数,把所有物品遍历一遍,要么选要么不选
    for(j=1;j<=m;j++){//j背包容量
      if(w[i]>j){//第i个物品的重量大于此时背包容量j
        f[i][j]=f[i-1][j];//那就不选i
      }else{//如果小于背包容量就选
        f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
          //在前i-1个物品基础上,面对第i个物品,你选了,那就要付出w[i]的代价,来换取价值为v[i]
          //如果你没选i号物品,那么你还有j背包容量供你选择i号物品前面的物品
          //如果你选了i号物品,那么你的背包容量将减少w[i],剩余j-w[i]供你选择i号物品前面的物品
          //因为是最优解问题,要寻找最大值,到底是选了i号物品价值更大还是不选i号物品价值更大
          //这里并不是选了就大,比如第i个物品是个石头,i-1是个钻石,你选了石头,钻石就放不开了,此时不选i号物品最优
      }
    }
  }
  printf("%d",f[n][m]);
}

完全背包问题

问题描述:给定一组物品,每个物品都有一个重量和一个价值,现有一个背包可以承载的最大重量为W。问可以选择哪些物品,使得在不超过背包容量的前提下,所携带物品的总价值最大。但每种物品可以无限取用。

状态定义:dp[i][j] 表示从前i个物品中选取一些放入容量为j的背包中,能够获得的最大价值。

状态转移方程:dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]] + v[i] if j >= w[i])。即,对于每个物品i,我们

考虑在当前背包容量j下,是否取用物品i,取用的话,可以取1个、2个...直到背包装不下为止。

初始化:dp[0][j] = 0,即没有物品时,任何容量的背包价值都为0。

遍历顺序:先遍历背包容量,再遍历物品。


多重背包问题

还有一种叫做多重背包问题,在多重背包问题中,每种物品都有限定的数量,不再是仅有一个,而是有多个。问题的描述如下:

给定一个背包容量为C,有n种物品,每种物品有重量w[i]、价值v[i]和数量s[i]。目标是选择物品放入背包,使得它们的总重量不超过背包容量,并且总价值最大。

这里不再详解,可以看我这一篇文章:细谈多重背包问题_n 种物品,每种物品有重量 w[i]、价值v[i],数量不限,背包容量为 b-CSDN博客

原题链接:细谈多重背包问题_n 种物品,每种物品有重量 w[i]、价值v[i],数量不限,背包容量为 b-CSDN博客

给定 V 种货币(单位:元),每种货币使用的次数不限。

不同种类的货币,面值可能是相同的。

现在,要你用这 V 种货币凑出 N 元钱,请问共有多少种不同的凑法。

输入格式

第一行包含两个整数 V 和 N。

接下来的若干行,将一共输入 V 个整数,每个整数表示一种货币的面值。

输出格式

输出一个整数,表示所求总方案数。

数据范围

1≤V≤25,

1≤N≤10000

答案保证在long long范围内。

输入样例:

3 10
1 2 5

输出样例:

10

解题思路:

这道题纯纯就是模板题了,就是背包dp求方案数的一个模板,做acwing蓝桥杯每日一题以来,从来没有见过这么简单的题,话不多说,直接上代码!

#include<iostream>
using namespace std;
typedef long long ll;
int v,n;
const int N = 1e4+5;
int a[N];
ll dp[N];
int main(){
  cin>>v>>n;
  for(int i=1;i<=v;i++){
    cin>>a[i];
  }
  dp[0]=1;//什么也没有也是一种方案
  for(int i=1;i<=v;i++){//枚举逐渐加入第i类钱
    for(int j=1;j<=n;j++){//枚举容量
      if(j>=a[i]){
        dp[j]=dp[j]+dp[j-a[i]];
      }
    }
  }
  cout<<dp[n]<<endl;
  return 0;
}



执笔至此,感触彼多,全文将至,落笔为终,感谢大家的支持。  

文章知识点与官方知识档案匹配,可进一步学习相关知识

相关文章
|
2月前
|
机器学习/深度学习 存储 算法
动态规划算法深度解析:0-1背包问题
0-1背包问题是经典的组合优化问题,目标是在给定物品重量和价值及背包容量限制下,选取物品使得总价值最大化且每个物品仅能被选一次。该问题通常采用动态规划方法解决,通过构建二维状态表dp[i][j]记录前i个物品在容量j时的最大价值,利用状态转移方程避免重复计算子问题,从而高效求解最优解。
404 1
|
2月前
|
算法 搜索推荐 Java
贪心算法:部分背包问题深度解析
该Java代码基于贪心算法求解分数背包问题,通过按单位价值降序排序,优先装入高价值物品,并支持部分装入。核心包括冒泡排序优化、分阶段装入策略及精度控制,体现贪心选择性质,适用于可分割资源的最优化场景。
242 1
贪心算法:部分背包问题深度解析
|
6月前
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
153 2
|
8月前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
230 15
|
8月前
|
存储 算法 数据处理
公司局域网管理中的哈希表查找优化 C++ 算法探究
在数字化办公环境中,公司局域网管理至关重要。哈希表作为一种高效的数据结构,通过哈希函数将关键值(如IP地址、账号)映射到数组索引,实现快速的插入、删除与查找操作。例如,在员工登录验证和设备信息管理中,哈希表能显著提升效率,避免传统线性查找的低效问题。本文以C++为例,展示了哈希表在局域网管理中的具体应用,包括设备MAC地址与IP分配的存储与查询,并探讨了优化哈希函数和扩容策略,确保网络管理高效准确。
|
4月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
137 0
|
6月前
|
监控 算法 数据处理
基于 C++ 的 KD 树算法在监控局域网屏幕中的理论剖析与工程实践研究
本文探讨了KD树在局域网屏幕监控中的应用,通过C++实现其构建与查询功能,显著提升多维数据处理效率。KD树作为一种二叉空间划分结构,适用于屏幕图像特征匹配、异常画面检测及数据压缩传输优化等场景。相比传统方法,基于KD树的方案检索效率提升2-3个数量级,但高维数据退化和动态更新等问题仍需进一步研究。未来可通过融合其他数据结构、引入深度学习及开发增量式更新算法等方式优化性能。
178 17
|
5月前
|
机器学习/深度学习 存储 算法
基于 C++ 布隆过滤器算法的局域网上网行为控制:URL 访问过滤的高效实现研究
本文探讨了一种基于布隆过滤器的局域网上网行为控制方法,旨在解决传统黑白名单机制在处理海量URL数据时存储与查询效率低的问题。通过C++实现URL访问过滤功能,实验表明该方法可将内存占用降至传统方案的八分之一,查询速度提升约40%,假阳性率可控。研究为优化企业网络管理提供了新思路,并提出结合机器学习、改进哈希函数及分布式协同等未来优化方向。
151 0
|
7月前
|
存储 监控 算法
基于 C++ 哈希表算法的局域网如何监控电脑技术解析
当代数字化办公与生活环境中,局域网的广泛应用极大地提升了信息交互的效率与便捷性。然而,出于网络安全管理、资源合理分配以及合规性要求等多方面的考量,对局域网内计算机进行有效监控成为一项至关重要的任务。实现局域网内计算机监控,涉及多种数据结构与算法的运用。本文聚焦于 C++ 编程语言中的哈希表算法,深入探讨其在局域网计算机监控场景中的应用,并通过详尽的代码示例进行阐释。
149 4
|
8月前
|
存储 算法 安全
企业员工数据泄露防范策略:基于 C++ 语言的布隆过滤器算法剖析[如何防止员工泄密]
企业运营过程中,防范员工泄密是信息安全领域的核心议题。员工泄密可能致使企业核心数据、商业机密等关键资产的流失,进而给企业造成严重损失。为应对这一挑战,借助恰当的数据结构与算法成为强化信息防护的有效路径。本文专注于 C++ 语言中的布隆过滤器算法,深入探究其在防范员工泄密场景中的应用。
181 8