DP:完全背包+多重背包问题

完全背包和01背包的区别就是:可以多次选

一、完全背包(模版)

【模板】完全背包_牛客题霸_牛客网

#include <iostream>
#include<string.h>
using namespace std;
const int N=1001;
int n,V,w[N],v[N],dp[N][N];
//dp[i][j]表示从前i个物品选,体积不超过j的最大价值
//dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i],dp[i-1][j-2v[i]]+2w[i]……)
//数学dp[i][j-v[i]]=max(dp[i-1][j-v[i]],dp[i-1][j-2v[i]]+w[i]……)
//dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]])
int main() 
{cin>>n>>V;for(int i=1;i<=n;++i) cin>>v[i]>>w[i];//解决第一问for(int i=1;i<=n;++i)for(int j=1;j<=V;++j){dp[i][j]=dp[i-1][j];if(j>=v[i]) dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i]);}  cout<<dp[n][V]<<endl;//解决第二问 //dp[i][j]表示从前i个物品选,体积正好为j的最大价值memset(dp,0,sizeof dp);//约定-1表示状态选不到 当i=0时 j>=1时  必然是没有状态的for(int j=1;j<=V;++j) dp[0][j]=-1;for(int i=1;i<=n;++i)for(int j=1;j<=V;++j){dp[i][j]=dp[i-1][j];if(j>=v[i]&&dp[i][j-v[i]]!=-1) dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i]);}  cout<<(dp[n][V]==-1?0:dp[n][V])<<endl;return 0;
}

滚动数组的优化策略:

 区分:01背包的优化得是从右往左,而完全背包的优化得是从左往右

#include <iostream>
#include<string.h>
using namespace std;
const int N=1001;
int n,V,w[N],v[N],dp[N];
//dp[i][j]表示从前i个物品选,体积不超过j的最大价值
//dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i],dp[i-1][j-2v[i]]+2w[i]……)
//数学dp[i][j-v[i]]=max(dp[i-1][j-v[i]],dp[i-1][j-2v[i]]+w[i]……)
//dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]])
int main()  //优化必须要从左往右
{cin>>n>>V;for(int i=1;i<=n;++i) cin>>v[i]>>w[i];//解决第一问for(int i=1;i<=n;++i)for(int j=v[i];j<=V;++j)dp[j]=max(dp[j],dp[j-v[i]]+w[i]);cout<<dp[V]<<endl;//解决第二问 //dp[i][j]表示从前i个物品选,体积正好为j的最大价值memset(dp,0,sizeof dp);//约定-1表示状态选不到 当i=0时 j>=1时  必然是没有状态的for(int j=1;j<=V;++j) dp[j]=-0x3f3f3f3f;for(int i=1;i<=n;++i)for(int j=v[i];j<=V;++j)dp[j]=max(dp[j],dp[j-v[i]]+w[i]);cout<<(dp[V]<0?0:dp[V])<<endl;return 0;
}

 二、零钱兑换

. - 力扣(LeetCode)

class Solution {
public:int coinChange(vector<int>& coins, int amount) {//dp[i][j]表示从前i个里面选 正好凑成j所需要的最少硬币个数//如果不选i dp[i-1][j]//选1个i   dp[i-1][j-coins[i-1]]+1//dp[i][j]=min(dp[i-1][j],dp[i-1][j-coins[i-1]]+1,dp[i-1][j-2coins[i-1]]+2……)//dp[i][j-coins[i-1]]=min(dp[i-1][j-coins[i-1]],dp[i-1][j-2coins[i-1]]+1……)//dp[i][j]=min(dp[i-1][j],dp[i][j-coins[i-1]]+1)const int INF=0x3f3f3f3f;int n=coins.size();vector<vector<int>> dp(n+1,vector<int>(amount+1));for(int j=1;j<=amount;++j) dp[0][j]=INF;for(int i=1;i<=n;++i)for(int j=1;j<=amount;++j){dp[i][j]=dp[i-1][j];if(j>=coins[i-1])  dp[i][j]=min(dp[i][j],dp[i][j-coins[i-1]]+1);}return dp[n][amount]>=INF?-1:dp[n][amount];}
};

 滚动数组优化:

class Solution {
public:int coinChange(vector<int>& coins, int amount) {//dp[i][j]表示从前i个里面选 正好凑成j所需要的最少硬币个数//如果不选i dp[i-1][j]//选1个i   dp[i-1][j-coins[i-1]]+1//dp[i][j]=min(dp[i-1][j],dp[i-1][j-coins[i-1]]+1,dp[i-1][j-2coins[i-1]]+2……)//dp[i][j-coins[i-1]]=min(dp[i-1][j-coins[i-1]],dp[i-1][j-2coins[i-1]]+1……)//dp[i][j]=min(dp[i-1][j],dp[i][j-coins[i-1]]+1)const int INF=0x3f3f3f3f;int n=coins.size();vector<int> dp(amount+1,INF);dp[0]=0;for(int i=1;i<=n;++i)for(int j=coins[i-1];j<=amount;++j)dp[j]=min(dp[j],dp[j-coins[i-1]]+1);return dp[amount]>=INF?-1:dp[amount];}
};

三、零钱兑换II

. - 力扣(LeetCode)

class Solution {
public:int change(int amount, vector<int>& coins) {//dp[i][j]表示从前i个硬币选,正好可以凑成总金额的硬币组合数//如果i不选 dp[i][j]+=dp[i-1][j]//如果i选1个 dp[i][j]+=dp[i-1][j-coins[i-1]]//dp[i][j]+=dp[i-1][j-coins[i-1]]+=dp[i-1][j-2coins[i-1]]……//dp[i][j]+=dp[i][j-coins[i-1]]int n=coins.size();//分析初始化 当j=0 都是一种选法  当i=0时 无论如何凑不出j 状态无效vector<vector<int>> dp(n+1,vector<int>(amount+1));dp[0][0]=1;for(int i=1;i<=n;++i)for(int j=0;j<=amount;++j) //不会越界,可以从0开始{dp[i][j]+=dp[i-1][j];if(j>=coins[i-1]) dp[i][j]+=dp[i][j-coins[i-1]];}return dp[n][amount];}
};

滚动数组做优化:

class Solution {
public:int change(int amount, vector<int>& coins) {//dp[i][j]表示从前i个硬币选,正好可以凑成总金额的硬币组合数//如果i不选 dp[i][j]+=dp[i-1][j]//如果i选1个 dp[i][j]+=dp[i-1][j-coins[i-1]]//dp[i][j]+=dp[i-1][j-coins[i-1]]+=dp[i-1][j-2coins[i-1]]……//dp[i][j]+=dp[i][j-coins[i-1]]int n=coins.size();//分析初始化 当j=0 都是一种选法  当i=0时 无论如何凑不出j 状态无效vector<int> dp(amount+1);dp[0]=1;for(int i=1;i<=n;++i)for(int j=coins[i-1];j<=amount;++j) //不会越界,可以从0开始dp[j]+=dp[j-coins[i-1]]; //+= 0不会影响填表return dp[amount];}
};

四、完全平方数

. - 力扣(LeetCode)

class Solution {
public:
//不能用贪心策略 比如说1 4 9   组成12    444比9111好int numSquares(int n) {//1 4 9 16 25……//dp[i][j]表示从前i个数选,刚好为j的最少数量const int INF=0x3f3f3f3f;int m=sqrt(n);vector<int> dp(n+1,INF);//i=0的时候 不可能凑成j  j=0时 i取1dp[0]=0;for(int i=1;i<=m;++i)for(int j=i*i;j<=n;++j)dp[j]=min(dp[j],dp[j-i*i]+1);return dp[n]; //一定能选得到,因为1是平方数 所以必然能凑出来}
};

五、数位成本和为目标值的最大数字(经典dp还原)

. - 力扣(LeetCode)

class Solution {
public:string largestNumber(vector<int>& nums, int t) {//考虑数值长度问题,每个数字有相应成本,且长度均为1 //有若干物品,求给定费用下所能选择的最大价值  (完全背包)//得到的就是最大位数 然后从后往前想办法还原回来vector<int> dp(t+1,-0x3f3f3f3f);//会有不存在的状态//dp[i][j]表示前i个数选择 正好为j的最大选择数目dp[0]=1;for(int i=1;i<=9;++i)for(int j=nums[i-1];j<=t;++j)dp[j]=max(dp[j],dp[j-nums[i-1]]+1);//此时 dp[t]里存的就是选择的最大位数 然后要想办法进行还原if(dp[t]<0) return "0";string ret;//开始还原 从后往前还原for(int i=9;i>=1;--i){int u=nums[i-1];while(t>=u&&dp[t]==dp[t-u]+1)//说明选到这个数了{ret+=to_string(i);t-=u;}}return ret;}
};

六、获得分数的方法数(多重背包)

. - 力扣(LeetCode)

 该种类型题的具体分析请看第7题!!

class Solution {
public:const int MOD=1e9+7;int waysToReachTarget(int target, vector<vector<int>>& types) {//dp[i][j]表示从前i个数选 恰好分数为j的方案数 选择方式是types[1] //如果不选这个数 dp[i-1][j]//如果选 1个  dp[i-1][j-p[0]] //如果选2个  dp[i-1][j-2p[0]]int n=types.size();vector<vector<int>> dp(n+1,vector<int>(target+1));//初始化当i为0时 dp[0][0]=1;for(int i=1;i<=n;++i){int count=types[i-1][0],mark=types[i-1][1]; //count表示这道题的题数(选择次数)  mark表示这道题的分数for(int j=0;j<=target;++j){dp[i][j]=dp[i-1][j];for(int k=1;k<=count;++k){if(j>=k*mark) dp[i][j]=(dp[i][j]+dp[i-1][j-k*mark])%MOD;}}}return dp[n][target];}
};

滚动数组优化 

class Solution {
public:const int MOD=1e9+7;int waysToReachTarget(int target, vector<vector<int>>& types) {//dp[i][j]表示从前i个数选 恰好分数为j的方案数 选择方式是types[1] //如果不选这个数 dp[i-1][j]//如果选 1个  dp[i-1][j-p[0]] //如果选2个  dp[i-1][j-2p[0]]vector<int> dp(target+1);//初始化当i为0时 dp[0]=1;for(auto&p:types){int count=p[0],mark=p[1]; //count表示这道题的题数(选择次数)  mark表示这道题的分数       //会用到上一层的状态,所以滚动数组应该要从后往前for(int j=target;j>=0;--j){count=min(count,j/mark);for(int k=1;k<=count;++k)dp[j]=(dp[j]+dp[j-k*mark])%MOD;}}return dp[target];}
};

进阶优化:

class Solution {
public:const int MOD=1e9+7;int waysToReachTarget(int target, vector<vector<int>>& types) {//dp[i][j]表示从前i个数选 恰好分数为j的方案数 选择方式是types[1] //如果不选这个数 dp[i-1][j]//如果选 1个  dp[i-1][j-p[0]] //如果选2个  dp[i-1][j-2p[0]]//dp[i][j]+=dp[i-1][j-p[0]]……//dp[i][j-p[0]+=dp[i-1]][j-]vector<int> dp(target+1);//初始化当i为0时 dp[0]=1;for(auto&p:types){int count=p[0],mark=p[1]; //count表示这道题的题数(选择次数)  mark表示这道题的分数       //会用到上一层的状态,所以滚动数组应该要从后往前for(int j=mark;j<=target;++j)dp[j]=(dp[j]+dp[j-mark])%MOD;for(int j=target;j>=(count+1)*mark;--j)dp[j] = (dp[j] - dp[j - mark*(count + 1)] + MOD) % MOD; // 两个同余前缀和的差//防止搞出负数}return dp[target];}
};

七、带和限制的子多重集合的数目(经典多重背包模版题)

. - 力扣(LeetCode)

 直接做滚动数组优化:

class Solution {
public:const int MOD=1e9+7;int countSubMultisets(vector<int>& nums, int l, int r) {//01背包 每个数选或者不选 限制范围是l-r//dp[i][j]表示从前i个数选  凑成和恰好为j//但是需要一个哈希表来帮助我们知道每个数究竟可以选多少次unordered_map<int,int> hash;int total=0;for(auto&e:nums) {total+=e;++hash[e];}if(l>total) return 0;r=min(r,total);vector<int> dp(r+1);//初始化 i=0时 无数可选dp[0]=hash[0]+1;hash.erase(0);int t=0;for(auto[x,c]:hash) //x是数 c是他的限制次数for(int j=r;j>=x;--j){c=min(c,j/x);for(int k=1;k<=c;++k)    //费时间 想办法用新的状态dp[j]=(dp[j]+dp[j-k*x])%MOD; }int sum=0;for(int j=l;j<=r;++j)sum=(sum+dp[j])%MOD;return sum;}
};

我们会发现由于数据量太大,用循环会超时,因此我们在这里不能用k那一层循环!!得换个方式

class Solution {
public:const int MOD=1e9+7;int countSubMultisets(vector<int>& nums, int l, int r) {//01背包 每个数选或者不选 限制范围是l-r//dp[i][j]表示从前i个数选  凑成和恰好为j//但是需要一个哈希表来帮助我们知道每个数究竟可以选多少次//类比完全背包的状态 dp[]unordered_map<int,int> hash;int total=0;for(auto&e:nums) {total+=e;++hash[e];}if(l>total) return 0;r=min(r,total);vector<int> dp(r+1);dp[0]=hash[0]+1;hash.erase(0);// dp[i][j]+=  dp[i-1][j-x]+dp[i-1][j-2*x]……// dp[i][j-x]+=dp[i-1][j-2x]+dp[i-1][j-3x]……int sum=0;for(auto[x,c]:hash){sum = min(sum+x*c,r);//目前为止 能选的元素和之多为sum for (int j = x; j <= sum; j++)dp[j] = (dp[j] + dp[j - x]) % MOD; // 原地计算同余前缀和for (int j =sum;j >= x * (c + 1); j--)dp[j] = (dp[j] - dp[j - x * (c + 1)] + MOD) % MOD; // 两个同余前缀和的差//防止搞出负数}int ret=0;for(int j=l;j<=r;++j)ret=(ret+dp[j])%MOD;return ret;}
};

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/856784.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

openstack使用

1.若虚机带磁盘&#xff0c;先卸载磁盘 for i in cinder list --all-tenants |awk {print $2} |grep -v ID|grep -v ^$; do jcinder list --all |grep $i | awk {print $16} |grep -v Attached|grep -v ^$ nova volume-detach $j $i done 2.删除磁盘 for i in cinder list …

【机器学习 复习】第6章 支持向量机(SVM)

一、概念 1.支持向量机&#xff08;support vector machine&#xff0c;SVM&#xff09;&#xff1a; &#xff08;1&#xff09;基于统计学理论的监督学习方法&#xff0c;但不属于生成式模型&#xff0c;而是判别式模型。 &#xff08;2&#xff09;支持向量机在各个领域内的…

CentOS Linux 7系统中离线安装MySQL5.7步骤

预计数据文件存储目录为&#xff1a;/opt/mysql/data 1、文件下载&#xff1a; 安装文件下载链接&#xff1a;https://downloads.mysql.com/archives/community/ 2、检查当前系统是否安装过MySQL [rootcnic51 mysql]# rpm -qa|grep mariadb mariadb-libs-5.5.68-1.el7.x86_6…

详释 Promise

当涉及到处理异步操作时&#xff0c;JavaScript 中的 Promise 是一个非常强大且常用的工具。下面详细解释 Promise 的相关内容&#xff0c;并举例说明&#xff1a; 1. 解决回调地狱的问题 Promise 的链式调用风格可以有效解决回调地狱的问题&#xff0c;使得代码更加清晰和易…

xss-lab靶场level1-level10

level1&#xff1a; 无过滤形式 直接 <script>window.alert(123)</script> level2: htmlspecialchars函数将预定义的小于和大于号转换为html实体 < &#xff08;小于&#xff09;成为 < > &#xff08;大于&#xff09;成为 > 源代码 <?…

深入探索Llama 2:下一代开源语言模型的革新与影响

Llama 2是Meta AI发布的一款先进的开源大模型&#xff0c;属于大型语言模型&#xff08;LLM&#xff09;类别。它是Transformer架构的一种变体&#xff0c;经过预先训练并在多种文本和代码数据集上进行微调&#xff0c;旨在提升功能和安全性。Llama 2的关键特点包括&#xff1a…

06. 多线程 yield 方法

1. 前言 本节对 yield 方法进行深入的剖析&#xff0c;主要内容点如下&#xff1a; 首先要了解什么是 CPU 执行权&#xff0c;因为 yield 方法与 CPU 执行权息息相关&#xff1b;了解 yield 方法的作用&#xff0c;要明确 yield 方法的使用所带来的运行效果&#xff1b;了解什…

简述http/https、tcp/ip、SSL/TLS介绍

HTTP/HTTPS、TCP和IP之间的区别主要体现在它们的作用层次、功能特点以及在网络通信中的角色。 一. 作用层次&#xff1a; HTTP/HTTPS&#xff1a;HTTP&#xff08;Hyper Text Transfer Protocol&#xff0c;超文本传输协议&#xff09;和HTTPS&#xff08;HTTP Secure&#x…

跨区域文件管控解决方案,一文了解

跨区域文件管控是一个涉及在不同地域或区域之间管理和控制文件的过程&#xff0c;它包括安全性、合规性和管理效率等多个方面。以下是一些关键的考量因素&#xff1a; 1.安全性&#xff1a;确保在传输过程中文件不被截获、篡改或泄露。使用加密技术保护文件&#xff0c;并确保传…

云呼叫中心系统能帮企业做哪些事?

在云计算时代大环境的影响&#xff0c;各大企业也都企图将云计算融入企业业务中&#xff0c;智能化不只可以提高企业产能、提高服务效率&#xff0c;更能发掘更高的品牌价值。云计算不断深入企业内部&#xff0c;尤其在劳动密集型的产业中&#xff0c;优势更加明显。以电销为例…

mysql 慢sql优化记录

最近在分析一条SQL&#xff0c;这条SQL执行时间去到2秒以上。SQL如下&#xff1a; selectcount(d.id) fromt_msg d whered.userid12456 and d.isread0 AND d.msgnumber<> NEW-JCPT003 表上索引有 idx_userid(userid)&#xff0c;这条SQL是一条比较标准的统计…

【初阶数据结构】深入解析带头双向循环链表:探索底层逻辑

&#x1f525;引言 本篇将介绍带头双向循环链表底层实现以及在实现中需要注意的事项&#xff0c;帮助各位在使用过程中根据底层实现考虑到效率上问题和使用时可能会导致的错误使用 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔…

昇腾Ascend C算子开发

Ascend C的算子实现主要包含两个部分&#xff1a; ● Host侧Tiling实现 由于NPU中AI Core内部存储无法完全容纳算子输入输出的所有数据&#xff0c;需要每次搬 运一部分输入数据进行计算然后搬出&#xff0c;再搬运下一部分输入数据进行计算&#xff0c;这个 过程就称之为Tilin…

C#使用NPOI库实现Excel的导入导出操作——提升数据处理效率的利器

文章目录 一、NPOI库简介二、安装与引入三、Excel的导入操作1.CSV格式导入2.XLS格式导入3. XLSX格式导入 四、Excel的导出操作1. CSV格式导出2. XLS格式导出3. XLSX格式导出 五、NPOI库的应用优势与改进方向总结 在日常工作学习中&#xff0c;我们经常需要处理Excel文件&#x…

AIX小机环境如何给ASM添加磁盘

前面几篇介绍了HPUX,Solaris平台上RAC集群ASM如何添加磁盘的 &#xff0c;三大UNIX平台只差AIX&#xff0c;本文介绍AIX平台RAC 添加ASM磁盘 environment&#xff1a; AIX 6.1 oracle 10.0.2.4 2 nodes RAC (storage HP-6100 FC disk) 1. 存储划盘&#xff0c;并将盘赋予…

[Day 16] 區塊鏈與人工智能的聯動應用:理論、技術與實踐

計算機視覺技術在AI中的應用 簡介 計算機視覺&#xff08;Computer Vision&#xff0c;CV&#xff09;是人工智能&#xff08;AI&#xff09;中一個重要且快速發展的領域&#xff0c;它使得機器能夠理解和解釋視覺信息。隨著硬件計算能力的提升和深度學習方法的興起&#xff…

紫光展锐芯片进入烧录模式

实验平台&#xff1a;移远通信SC200L搭载SMART-EVB-G5开发板 软件进入&#xff1a; SPRD平台芯片可以通过adb进入fastboot模式&#xff0c;由fastboot flash boot等指令烧录&#xff1a; $ adb root $ adb reboot fastboot $ fastboot flash boot boot.img 由于usb传输一般都…

探索 Spring Boot 集成缓存功能的最佳实践

在线工具站 推荐一个程序员在线工具站&#xff1a;程序员常用工具&#xff08;http://cxytools.com&#xff09;&#xff0c;有时间戳、JSON格式化、文本对比、HASH生成、UUID生成等常用工具&#xff0c;效率加倍嘎嘎好用。 程序员资料站 推荐一个程序员编程资料站&#xff1a;…

《单元测试之道Java版——使用JUnit》学习笔记汇总

前言 主要用来记录《单元测试之道Java版——使用JUnit》书中的一些必要知识&#xff0c;方便后期编程使用。 目录 序言你的首个单元测试使用Junit编写测试测试哪些内容&#xff1a;Right-BICEPCORRECT边界条件使用Mock对象好的测试所具有的品质在项目中进行测试设计话题 后…

使用kibana创建索引的时候报错处理

报错信息&#xff1a;The index pattern youve entered doesnt match any indices. You can match your 1 index, below. 使用kibana创建索引的时候&#xff0c;无法进行下一步创建操作&#xff0c;出现这种情况有很多种情况&#xff0c;每个人遇到的问题会不一样。 第一种&am…