20250908 背包DP总结

引子

~ 我们都有一个家,名字叫背包 ~

背包DP

顾名思义,背包DP是用来解决背包最值问题的。题目会给出背包的容量,以及几个物品的属性,比如重量,价值,限额等等,具体是什么看题目。

01背包

01背包就是每个物品只能选择拿还是不拿。怎么实现呢?我们设dp[i]dp[i]dp[i]表示当背包容量为iii是可以获得的最值,那么答案就是dp[w]dp[w]dp[w],其中www代表背包容量。

首先,我们枚举每一个物品,然后再枚举背包容量,看目前的背包装不装的下这个物品,如果装得下,那么用装这个物品之前剩余的背包的容量的最值加上这个物品的价值更新目前的dp[j]dp[j]dp[j],动态转移方程 dp[j]=max(dp[j],dp[j−w[i]]+q[i])dp[j]=max(dp[j],dp[j-w[i]]+q[i])dp[j]=max(dp[j],dp[jw[i]]+q[i])

洛谷 P1048 采药

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

当然不能啦01背包的模板,真没啥好说的,动态转移方程都出了。

时间复杂度O(nt)O(nt)O(nt)

#include<bits/stdc++.h>
using namespace std;
struct cy{int t,j;
}a[105];
int dp[1005];
int main(){int t,n;cin>>t>>n;for(int i=1;i<=n;i++){cin>>a[i].t>>a[i].j;}for(int i=1;i<=n;i++){for(int j=t;j>=0;j--){if(j>=a[i].t){dp[j]=max(dp[j],dp[j-a[i].t]+a[i].j);}}}cout<<dp[t];return 0;
}

完全背包

完全背包就是每个物品可以拿无数个。基本和01背包一致,只是背包容量要从小到大枚举。为什么呢?

个人认为,从大到小枚举,因为背包容量更大的只可能被背包容量更小的更新,而且是先更新背包容量更大的,所以一个物品只会被拿一次。

相反,从小到大枚举,因为背包容量更小的可以更新背包容量更大的,而且是先更新背包容量更小的,所以一个物品会被拿很多次。

洛谷 P1616 疯狂的采药

LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是 LiYuxiang,你能完成这个任务吗?

此题和原题的不同点:

  1. 每种草药可以无限制地疯狂采摘。
  2. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!

当然不能啦完全背包的模板,稍微注意一下要开long long。

时间复杂度O(nt)O(nt)O(nt)

#include<bits/stdc++.h>
using namespace std;
struct cy{long long t,j;
}a[10005];
long long b[10000005];
int main(){int t,n;cin>>t>>n;for(int i=1;i<=n;i++){cin>>a[i].t>>a[i].j;} for(int i=1;i<=n;i++){for(int j=0;j<=t;j++){if(j>=a[i].t){b[j]=max(b[j],b[j-a[i].t]+a[i].j);}}}cout<<b[t];return 0;
}

多重背包

多重背包就是第i个物品最多可以拿p[i]次,大小为w[i],价值为q[i]。一种做法,把多重背包转换成01背包来写。

首先枚举每一个物品,然后从大到小枚举背包容量,接着枚举拿多少个这个物品,判断目前的背包容量装不装的下这么多个物品,装得下就用装这几个物品之前的最值加上这几个物品的价值更新目前的dp。dp[j]=max(dp[j],dp[j−k∗w[i]]+k∗q[i]dp[j]=max(dp[j],dp[j-k*w[i]]+k*q[i]dp[j]=max(dp[j],dp[jkw[i]]+kq[i]

但是,但是,时间复杂度就是O(VΣp[i])O(VΣp[i])O(VΣp[i])了,在一些题目里会超时。怎么办呢?于是就有了二进制优化。

洛谷 P1776 宝物筛选

终于,破解了千年的难题。小 FF 找到了王室的宝物室,里面堆满了无数价值连城的宝物。

这下小 FF 可发财了,嘎嘎。但是这里的宝物实在是太多了,小 FF 的采集车似乎装不下那么多宝物。看来小 FF 只能含泪舍弃其中的一部分宝物了。

小 FF 对洞穴里的宝物进行了整理,他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值,之后开始了宝物筛选工作:小 FF 有一个最大载重为WWW 的采集车,洞穴里总共有nnn种宝物,每种宝物的价值为vi​v_i​vi,重量为wiw_iwi​,每种宝物有mim_imi件。小 FF 希望在采集车不超载的前提下,选择一些宝物装进采集车,使得它们的价值和最大。

多重背包加 二进制 or 单调队列 优化即可。

时间复杂度O(nm)O(nm)O(nm)

#include<bits/stdc++.h>//二进制优化多重背包
using namespace std;
int dp[1000005],w[1000005],v[1000005],n,m,ans,cnt=1;
int main(){cin>>n>>m;for(int i=1;i<=n;i++){int a,b,c;cin>>a>>b>>c;for(int j=1;j<=c;j<<=1){v[++cnt]=j*a;w[cnt]=j*b;c-=j;}if(c){v[++cnt]=a*c;w[cnt]=b*c; }}for(int i=1;i<=cnt;i++){for(int j=m;j>=w[i];j--){dp[j]=max(dp[j],dp[j-w[i]]+v[i]);}        }cout<<dp[m];return 0;
}

混合背包

太恐怖了混合背包,每一个物品,它可以拿无数次或拿有限次。其实就是把前面三种背包捆起来,枚举每个物品时判断一下是可以拿无数次还是可以拿有限次,是无数次就用完全背包,是有限次就用多重背包。

洛谷 P1833 樱花

爱与愁大神后院里种了nnn棵樱花树,每棵都有美学值Ci(0<Ci≤200)C_i(0<C_i≤200)Ci(0<Ci200)。爱与愁大神在每天上学前都会来赏花。爱与愁大神可是生物学霸,他懂得如何欣赏樱花:一种樱花树看一遍过,一种樱花树最多看Pi(0≤Pi≤100)P_i(0≤P_i≤100)Pi(0Pi100)遍,一种樱花树可以看无数遍。但是看每棵樱花树都有一定的时间Ti(0<Ti≤100)T_i(0<T_i≤100)Ti(0<Ti100)。爱与愁大神离去上学的时间只剩下一小会儿了。求解看哪几棵樱花树能使美学值最高且爱与愁大神能准时(或提早)去上学。

混合背包模板题,需要赘述吗?

时间复杂度O(nt)O(nt)O(nt)

#include<bits/stdc++.h>
using namespace std;
struct node{int t,c,p;
}a[10005];
long long dp[1005];
int main(){string s1,s2;cin>>s1>>s2;int t1=0,t2=0,t3=0,t4=0;//这只是一些细节,可以直接跳过if(s1.size()==4){t1=s1[0]-48;t2=(s1[2]-48)*10+s1[3]-48;}else{t1=(s1[0]-48)*10+s1[1]-48;t2=(s1[3]-48)*10+s1[4]-48;}if(s2.size()==4){t3=s2[0]-48;t4=(s2[2]-48)*10+s2[3]-48;}else{t3=(s2[0]-48)*10+s2[1]-48;t4=(s2[3]-48)*10+s2[4]-48;}int t=(t3-t1)*60+(t4-t2),n;//到这才算真正开始cin>>n;for(int i=1;i<=n;i++){cin>>a[i].t>>a[i].c>>a[i].p;}for(int j=1;j<=n;j++){if(a[j].p==0){//如果可以拿无数次for(int i=1;i<=t;i++){//完全背包if(i>=a[j].t){dp[i]=max(dp[i],dp[i-a[j].t]+a[j].c);}}}else{//不然就只能拿有限次数for(int i=t;i>=1;i--){//多重背包for(int k=1;k<=a[j].p;k++){if(i>=k*a[j].t){dp[i]=max(dp[i],dp[i-k*a[j].t]+a[j].c*k);}}}            }}cout<<dp[t];return 0;
}

完结撒花就怪了。。。。。。

好多例题

hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh……

咳咳,刚才有些脑抽了,巨佬别**……

洛谷 P1510 精卫填海

本题为改编题。

发鸠之山,其上多柘木。有鸟焉,其状如乌,文首,白喙,赤足,名曰精卫,其名自詨。是炎帝之少女,名曰女娃。女娃游于东海,溺而不返,故为精卫。常衔西山之木石,以堙于东海。——《山海经》

精卫终于快把东海填平了!只剩下了最后的一小片区域了。同时,西山上的木石也已经不多了。精卫能把东海填平吗?

事实上,东海未填平的区域还需要至少体积为 v 的木石才可以填平,而西山上的木石还剩下 n 块,每块的体积和把它衔到东海需要的体力分别为 k 和 m。精卫已经填海填了这么长时间了,她也很累了,她还剩下的体力为 c。

哇,01背包!看起来好高级啊!

千万不要想复杂了,其实只要把状态想清楚了就行了。我的做法是把dp[i]状态设为体力为i时可以填补的最大体积,那么最后的答案就是 ccc 减去符合条件 v≤dp[i]v≤dp[i]vdp[i] 的最小 iii

时间复杂度O(nc)O(nc)O(nc)

#include<bits/stdc++.h>
using namespace std;
int k[10005],m[10005],dp[10005];
int main(){int u,n,c;cin>>u>>n>>c;for(int i=1;i<=n;i++){cin>>k[i]>>m[i];}for(int j=1;j<=n;j++){for(int i=c;i>=0;i--){if(m[j]<=i){dp[i]=max(dp[i],dp[i-m[j]]+k[j]);}}}if(dp[c]<u){cout<<"Impossible";}else if(dp[0]>=u){//可能只需要填0体积或有的木石所需体力为0cout<<c;}else{for(int i=1;i<=c;i++){if(dp[i]>=u){cout<<c-i;return 0;}}}return 0;
}

洛谷 P1455 搭配购买

明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有 n 朵云,云朵已经被老板编号为 1,2,3,…,n,并且每朵云都有一个价值。

但是商店的老板是个很奇怪的人,他会告诉你一些云朵要搭配起来买才卖,也就是说买一朵云则与这朵云有搭配的云都要买。电脑组的你觉得这礼物实在是太新奇了,但是你的钱是有限的,所以你肯定是想用现有的钱买到尽量多价值的云。

非常鬼畜的一道题,但并不难。首先题目告诉我们一些云朵必须一起买,相信你一定想到了并查集,没错,就是并查集!好吧,标签上面就有……

首先我们设好并查集数组的初始值,然后接到m个搭配的时候用并查集函数找到这两朵云的祖宗,然后让他们认祖归宗,完了之后看有几个祖宗,用一个数组统计起来。

接下来就是强连通分量了,把每个祖宗相同的点连起来,看成一整个点,再用两个数组记录这几个点的总价钱和总价值,然后就套上01背包模板即可得出答案。

时间复杂度O(cntw)O(cntw)O(cntw)

#include<bits/stdc++.h>
using namespace std;
int c[10005],d[10005],fa[10005],dp[10005];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);
}
int q[10005],g[10005],gp[10005];
int main(){int n,m,w;cin>>n>>m>>w;for(int i=1;i<=n;i++){cin>>c[i]>>d[i];fa[i]=i;}for(int i=1;i<=m;i++){int u,v;cin>>u>>v;u=find(u),v=find(v);if(u!=v){fa[u]=fa[v];}}for(int i=1;i<=n;i++){if(fa[i]==i){gp[++gp[0]]=i;}}for(int i=1;i<=n;i++){for(int j=1;j<=gp[0];j++){if(find(i)==gp[j]){q[j]+=c[i];g[j]+=d[i];}}}for(int j=1;j<=gp[0];j++){for(int i=w;i>=0;i--){if(i>=q[j]){dp[i]=max(dp[i],dp[i-q[j]]+g[j]);}}}cout<<dp[w];return 0;
}

CF189A Cut Ribbon

波利卡普有一条长度为n的丝带。他想按照以下两个条件切割这条丝带:

  1. 切割后每段丝带的长度必须是a、b或c
  2. 切割后的丝带段数要尽可能多

请帮助波利卡普计算出满足条件的切割方式下,最多能得到多少段丝带。

别想着用分支结构,因为他最多可以分成4000段……

感觉好简单哪,不就是完全背包吗?我们设dp[i]为丝带长度为i时可以分成的最多段数,那么答案就是dp[n]。

所谓物品,在这里就是a,b,c,把它分成几段,就是拿几个a,拿几个b,拿几个c,那么在枚举丝带长度时就可以看减去这一段是否可以分成若干个a,b,c,可以就用dp[i−a,b,c]+1dp[i-a,b,c]+1dp[ia,b,c]+1更新dp[i]dp[i]dp[i]

时间复杂度O(n)O(n)O(n)

#include<bits/stdc++.h>
using namespace std;
long long dp[8005];
int main(){long long n,a,b,c;cin>>n>>a>>b>>c;if(b>c){//注意,为了使分的段数尽量的多,所以我们一定要从长度更小的开始 dpswap(b,c);}if(a>b){swap(a,b);}for(int i=1;i<=n;i++){if(i==a||(dp[i-a+n]&&i>=a)){dp[i+n]=max(dp[i+n],dp[i-a+n]+1);//左移战术,百战不殆!}if(i==b||(dp[i-b+n]&&i>=b)){dp[i+n]=max(dp[i+n],dp[i-b+n]+1);}if(i==c||(dp[i-c+n]&&i>=c)){dp[i+n]=max(dp[i+n],dp[i-c+n]+1);}}cout<<dp[n+n];return 0;
}

洛谷 P6771 [USACO05MAR] Space Elevator 太空电梯

奶牛们要去太空了!它们打算用方块建造一座太空电梯。现在它们有 N 种方块,第 i 种方块有一个特定的高度 hih_ihi ,一定的数量 cic_ici 。为了防止宇宙射线破坏方块,第 i 种方块的任何部分不能超过高度 aia_iai 。请用这些方块堆出最高的太空电梯。

话说这些奶牛越来越猎奇了……

说白了就是个多重背包嘛,也就套了个太空电梯的壳子,不过这回dp是一个bool数组,也就是dp[i]表示是否可以达到高度 i ,那么当j>=k*h[i],状态转移方程:dp[j]∣=dp[j−k∗a[i].h]dp[j] |=dp[j-k*a[i].h]dp[j]=dp[jka[i].h]

时间复杂度O(nkΣa[i])O(nkΣa[i])O(nkΣa[i])

#include<bits/stdc++.h>
using namespace std;
struct node{int h,a,c;
}a[405];
bool cmp(node x,node y){return x.a<y.a;
}
bool dp[40005];
int main(){int n;cin>>n;for(int i=1;i<=n;i++){cin>>a[i].h>>a[i].a>>a[i].c;}sort(a+1,a+1+n,cmp);//排个序才能更优dp[0]=1;for(int i=1;i<=n;i++){for(int j=a[i].a;j>=a[i].h;j--){for(int k=1;k<=a[i].c;k++){if(j>=k*a[i].h){dp[j]|=dp[j-k*a[i].h];}}}}for(int i=a[n].a;i>=0;i--){if(dp[i]){cout<<i;return 0;}}return 0;
}

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

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

相关文章

Redis持久化之RDB:快照机制原理、配置与最佳实践

Redis持久化之RDB&#xff1a;快照机制原理、配置与最佳实践 1. RDB持久化概述 1.1 什么是RDB RDB&#xff08;Redis Database&#xff09;是Redis的默认持久化方式&#xff0c;它在指定的时间间隔内生成数据集的快照&#xff08;snapshot&#xff09;&#xff0c;并将快照保…

daily notes[44]

文章目录基础references基础 hello,world是几乎所有编程语言的第一例子&#xff0c;rust也不例外。但和其它语言不一样&#xff0c;Rust的源码最好拥有自己的项目目录。 $ mkdir ~/pro $ cd ~/pro $ mkdir helloWorld $ cd helloWorld源代码文件名为main.rs&#xff0c;内容如…

JavaScript对象创建方式完全指南:从原始到现代的演进之路

前言 作为一名前端开发者&#xff0c;JavaScript中对象创建是很重要。在JavaScript这门基于原型的语言中&#xff0c;对象几乎无处不在。今天&#xff0c;我将带领大家回顾JavaScript对象创建的7种方式&#xff0c;从最原始的字面量到现代的ES6 class&#xff0c;每一步演进都解…

基于单片机的无线水塔监控系统设计(论文+源码)

本设计为基于单片机的无线水塔监控系统设计&#xff0c;主要由以下几部分组成&#xff1a;均采用STC89C52RC单片机为主控&#xff1b;主机&#xff1a;NRF24L01无线通讯模块&#xff0c;1602LCD液晶显示屏。从机&#xff1a;NRF24L01无线通讯模块&#xff0c;水位传感器&#x…

凌晨0-3点不睡,你熬的不是夜,是人生!

“熬夜”这个词&#xff0c;早已成为现代生活的常态。有人为了工作加班到深夜&#xff0c;有人为了娱乐刷剧到天明&#xff0c;但你知道吗&#xff1f;熬夜最“要命”的时间段&#xff0c;其实是凌晨0点到凌晨3点。别以为只是少睡几个小时而已&#xff0c;这个时间段不睡&#…

大语言模型基石:Transformer

一、引言 如今火爆的 GPT、LLaMA、通义千问、ChatGLM 等大语言模型&#xff0c;背后都离不开一个核心架构——Transformer。 2017 年&#xff0c;Google 在论文《Attention Is All You Need》中首次提出 Transformer 模型&#xff0c;彻底改变了自然语言处理的发展方向。它摒…

【算法】【链表】160.相交链表--通俗讲解

算法通俗讲解推荐阅读 【算法–链表】83.删除排序链表中的重复元素–通俗讲解 【算法–链表】删除排序链表中的重复元素 II–通俗讲解 【算法–链表】86.分割链表–通俗讲解 【算法】92.翻转链表Ⅱ–通俗讲解 【算法–链表】109.有序链表转换二叉搜索树–通俗讲解 【算法–链表…

MySQL——库的操作

1、创建数据库语法&#xff1a;CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] ...] create_specification: [DEFAULT] CHARACTER SET charset_name [DEFAULT] COLLATE collation_name这里的CHARACTER SET表示指定数据库采用的字符集…

Python ast模块(Abstract Syntax Trees,抽象语法树)介绍及使用

文章目录 核心概念 基本使用流程 常用节点类型 示例代码 实际应用场景 注意事项 `ast.literal_eval()` 功能说明 适用场景 使用示例 限制与安全特性 与 `eval()` 的对比 总结 Python 的 ast 模块( Abstract Syntax Trees,抽象语法树)允许你解析、分析和修改 Python 代码的…

C++宽度优先搜索算法:队列与优先级队列

本期我们就来深入学习一下C算法中一个很重要的算法思想&#xff1a;宽度优先搜索算法 宽度优先算法是一个应用十分广泛的算法思想&#xff0c;涉及的领域也十分繁多&#xff0c;因此本篇我们先只涉猎它的一部分算法题&#xff1a;队列/优先级队列&#xff0c;后续我们会进一步地…

类的property属性

​​Python 中的 property 特性详解​​property 是 Python 中用于​​将方法转换为属性​​的装饰器&#xff0c;它允许开发者以访问属性的方式调用方法&#xff0c;同时可以添加逻辑控制&#xff08;如数据校验、计算属性等&#xff09;。以下是其核心用法和优势&#xff1a;…

【Redis#9】其他数据结构

引言 Redis 除了我们最常用的 String、Hash、List、Set、ZSet&#xff08;Sorted Set&#xff09; 这五种基本数据结构外&#xff0c;还提供了很多高级或特殊用途的数据结构/类型 &#xff0c;它们可以满足更复杂的业务需求。 ✅ Redis 的“五大基本数据结构”回顾类型特点Stri…

AutoGen——自定义Agent

目录引子自定义 AgentCountDownAgentArithmeticAgent在自定义 Agent 中使用自定义模型客户端让自定义 Agent 声明式化Selector Group Chat示例&#xff1a;网页搜索 / 数据分析代理&#xff08;Agents&#xff09;Workflow终止条件&#xff08;Termination Conditions&#xff…

【重定向和转发的核心理解】

重定向和转发 不废话&#xff1a; “转发” 的核心定义&#xff1a; 服务端内部主导跳转、客户端无感知&#xff08;仅 1 次请求&#xff09;、浏览器 URL 不改变&#xff0c;与传统 Web 开发中 “转发” 的本质逻辑完全一致&#xff0c;只是实现载体&#xff08;Nginx 路由层 …

生成对抗网络详解与实现

生成对抗网络详解与实现0. 前言1. GAN 原理2. GAN 架构3. 损失函数3.1 判别器损失3.2 生成器损失3.4 VANILLA GAN4. GAN 训练步骤0. 前言 生成对抗网络 (Generative Adversarial Network, GAN) 是图像和视频生成中的主要方法之一。在本节中&#xff0c;我们将了解 GAN 的架构、…

FPGA硬件开发-XPE工具的使用

目录 XPE 工具概述​ XPE 使用步骤详解​ 1. 工具获取与初始化​ 2. 器件选择与配置​ 3. 电源电压设置​ 4. 资源使用量配置​ 5. 时钟与开关活动配置​ 6. 功耗计算与报告生成​ 报告解读与电源设计优化​ 常见问题与最佳实践​ 与实际功耗的差异处理​ 工具版本…

CentOS 7.9 RAID 10 实验报告

文章目录CentOS 7.9 RAID 10 实验报告一、实验概述1.1 实验目的1.2 实验环境1.3 实验拓扑二、实验准备2.1 磁盘准备2.2 安装必要软件三、RAID 10阵列创建3.1 创建RAID 10阵列3.2 创建文件系统并挂载3.3 保存RAID配置四、性能基准测试4.1 初始性能测试4.2 创建测试数据集五、故障…

机器人逆运动学进阶:李代数、矩阵指数与旋转流形计算

做机器人逆运动学&#xff08;IK&#xff09;的时候&#xff0c;你迟早会遇到矩阵指数和对数这些东西。为什么呢&#xff1f;因为计算三维旋转的误差&#xff0c;不能简单地用欧氏距离那一套&#xff0c;那只对位置有效。旋转得用另一套方法——你需要算两个旋转矩阵之间的差异…

计算机视觉(opencv)实战十八——图像透视转换

图像透视变换详解与实战在图像处理中&#xff0c;透视变换&#xff08;Perspective Transform&#xff09; 是一种常见的几何变换&#xff0c;用来将图像中某个四边形区域拉伸或压缩&#xff0c;映射到一个矩形区域。常见应用场景包括&#xff1a;纠正拍照时的倾斜&#xff08;…