背包问题总结:双线程背包 RQNOJ329,202
来源:互联网 发布:淘宝有一加的旗舰店吗 编辑:程序博客网 时间:2024/05/22 06:13
所谓双线程背包,肯定就是对于一个物品,有两个需要考虑的量,个人对于双线程背包的题目自己还没有遇见比较难的,先放两个正推与逆推的例题好了。
例一:RQNOJ 329 刘翔加油
题目描述
刘翔因伤从北京奥运会的跑道上下来以后,十分的痛苦难过!全国人民看到后都为刘翔加油,支持和关心刘翔!因此,很多人写信来安慰他。没多久,就收到了一大堆信件,可他处理不了这么多,便找到ssxyh处理。ssxyh将信件分了n分,每份信件都有自己的,欣赏价值value,消耗时间time,消耗体力h,和得到的鼓舞w。观看信件必须按照价值递增(大于)的顺序观看,不一定需要全看,例如看了价值45之后就不能再看价值23的了。(为什么?,如果先看了小胡的信当然再看布什的信就不爽了,谁看得下去啊。。。。)可是,翔在伤病中,时间和体力都有限,分别为t,m,同时看完之后体力不能为0(会挂的。。)。这下ssxyh也犯难了,只好请求你帮忙,如何在这些条件下使刘翔获得最大的鼓舞呢??
其实我在此所述的双线程背包也属于01背包的一种变形。
对于题目最简单的状态设计就为dp[i][j][k]表示考虑到前i个,体力值为j,价值为k的最大鼓舞。可能有人会问怎么保证价值递增啊?为什么不sort一下呢?其实放进去的时候虽然不是价值递增的,可是当我们放进去再看的时候可以把它当作价值递增放进去的。当然题目数据似乎保证了不会有价值是一样的存在。
状态转移也很简单对于dp[i][j][k]会由dp[i-1][j-h[i]][k-tim[i]]转移而来,这时我们就发现了,其实这就是一个01背包!所以根据这个状态只会考虑j,k比当前j,k小的状态,所以倒序枚举可以成功压掉一维。
下附AC代码。
#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#define maxn 105using namespace std;int n,m,t;struct nod{ int val,tim,h,che;}hum[maxn];int dp[maxn][maxn]; int main(){scanf("%d%d%d",&n,&m,&t);for(int i=1;i<=n;i++)scanf("%d%d%d%d",&hum[i].val,&hum[i].tim,&hum[i].h,&hum[i].che);for(int i=1;i<=n;i++){for(int h=m;h>=hum[i].h+1;h--){for(int ti=t;ti>=hum[i].tim;ti--){dp[h][ti]=max(dp[h][ti],dp[h-hum[i].h][ti-hum[i].tim]+hum[i].che);}}}printf("%d\n",dp[m][t]);}
例二:RQNOJ 202 奥运火炬登珠峰
5月8日,在世界人民的共同关注下,象征着和平、友谊、圣洁的奥运火炬终于来到了世界之巅——珠穆朗玛峰……
登上珠峰可不是所有人都能办得了的,火炬手们为了登山要使用特殊的装备。他有一个带2种气体的气缸:一个为氧气,一个为氮气。让火炬手需要各种的数量的氧和氮。火炬手有一定数量的气缸。每个气缸都有重量和气体容量。火炬手为了完成传递需要特定数量的氧和氮。他完成传递所需气缸的总重的最低限度的是多少?
例如:火炬手有5个气缸。每行三个数字为:氧,氮的(升)量和气缸的重量:
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
如果火炬手需要5升的氧和60升的氮则总重最小为249 (1,2或者4,5号气缸)。
你的任务就是计算火炬手为了完成传递需要的气缸的重量的最低值。
其实这个题还是有一些很巧妙的地方的。
对于状态的设计,我们使用dp[i][j][k]表示考虑到前i个,氧气是j升,氮气为k升的最小价值。
那么我们如果使用顺推的方法,那么当前的状态就可以转移到dp[i+1][j+O2[i]][k+N2[i]]的这个状态了。最开始我们可能会理所应当将答案认为为dp[n][t][t],可是如果还记着小学的旅行团选车的一类问题,当时的选车可能座位坐不满但是价值更少,这里也可以用同样的思想,如果我们氧气和氮气买多了,如果价值还少那么也无妨。所以我们可以将数组开大,只要大于要求的氧气和氮气量更新答案即可。
下附AC代码。
#include <iostream>#include <stdio.h>#include <string.h>#define maxn 1005#define INF 10000000using namespace std;int o2,n2;int n;int ans=987654321;int dp[maxn][60][170];int v1[maxn],v2[maxn],w[maxn];int main(){ scanf("%d%d%d",&o2,&n2,&n); for(int i=0;i<n;i++) { cin>>v1[i]>>v2[i]>>w[i]; } memset(dp,-1,sizeof(dp)); dp[0][0][0]=0; for(int i=0;i<n;i++) { for(int j=0;j<=o2;j++) { for(int k=0;k<=n2;k++) { if(dp[i][j][k]!=-1) { if(dp[i+1][j][k]==-1 || dp[i+1][j][k]>dp[i][j][k]) { dp[i+1][j][k]=dp[i][j][k]; } if(dp[i+1][j+v1[i]][k+v2[i]]==-1 || dp[i+1][j+v1[i]][k+v2[i]]>dp[i][j][k]+w[i]) { dp[i+1][j+v1[i]][k+v2[i]]=dp[i][j][k]+w[i]; if(j+v1[i]>=o2 && k+v2[i]>=n2) ans=min(ans,dp[i+1][j+v1[i]][k+v2[i]]); } if(j>=o2 && k>=n2) ans=min(ans,dp[i][j][k]); } } } } cout<<ans<<endl;}
- 背包问题总结:双线程背包 RQNOJ329,202
- nyoj61(双线背包)
- 背包(01背包、完全背包、多重背包)问题总结
- 背包问题总结(01背包、完全背包、多重背包)
- 01背包问题总结
- 背包问题求解总结
- 01背包问题总结
- 完全背包问题总结
- 背包问题总结一
- 背包问题总结二
- 背包问题总结
- 背包问题总结
- 背包问题总结
- 背包问题总结
- 01背包问题总结
- 背包问题总结
- 背包问题全总结
- 背包问题总结篇
- 解决消息提示为undefined的方法及向后台提交数据的两种方法
- 周中训练笔记1
- Web性能优化规则
- 八月英语——Fearless
- 开发分层各层作用
- 背包问题总结:双线程背包 RQNOJ329,202
- Oracle异常汇总
- 随机森林
- 炮 HYSBZ
- bzoj 1264: [AHOI2006]基因匹配Match 树状数组
- 相机 镜头原理及其选型
- Leetcode OJ 23 Merge k Sorted Lists [Hard]
- 2017/8/31
- mysql无密码登录