背包提高练习题题解
前言
文中介绍了背包的提高练习,难度从黄到蓝。
T1-SCUBADIV - Scuba diver
题目描述
潜水员为了潜水要使用特殊的装备。
他有一种带
让潜水员下潜的深度需要各种的数量的氧和氮。潜水员为了完成他的工作需要特定数量的氧和氮。
一共有
输入/输出格式
输入文件的第一行,仅包含数据的组数
对于接下来的每一组数据:
第一行输入潜水员所需要的氧气量
第二行输入潜水员可选的氧气瓶的数目
接下来的
输出文件只有一行,即为答案。(注意要换行)
数据范围与约定
(它们都是整数)
样例 #1
样例输入 #1
1
5 60
5
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
样例输出 #1
249
Solution
其实就是二维的背包,相当于有两个体积。
此时我们可以定义
由于数据较小,边界设为
难度约为黄。
Code
#include<bits/stdc++.h>
using namespace std;
const int N =1e3+10;
int t,a,n,w1,w2,v,dp[N][N],ans=1e9;
int main() {
cin>>t>>a>>n;
memset(dp,0x3f,sizeof dp);dp[0][0]=0;
for(int i=1;i<=n;i++) {
cin>>w1>>w2>>v;
for(int j=500;j>=w1;j--)
for(int k=500;k>=w2;k--) {
dp[j][k]=min(dp[j][k],dp[j-w1][k-w2]+v);
if(j>=t&&k>=a&&dp[j][k]<1e9) ans=min(ans,dp[j][k]);
}
}
cout<<ans;
return 0;
}
T2-[USACO08NOV] Buying Hay S
题目描述
约翰的干草库存已经告罄,他打算为奶牛们采购
帮助约翰找到最小的开销来满足需要,即采购到至少
样例 #1
样例输入 #1
2 15
3 2
5 3
样例输出 #1
9
Solution
与一般题不同的是,本题要求干草数量(体积)至少为
- 最优解存在于
。
因为
在本题中为
难度约为黄。
Code
#include<bits/stdc++.h>
using namespace std;
const int N =5e5+10;
int t,a,n,w,v,dp[N],ans=1e6;
int main() {
cin>>n>>t;
memset(dp,0x3f,sizeof dp);dp[0]=0;
for(int i=1;i<=n;i++) {
cin>>w>>v;
for(int j=w;j<=5e4+5000;j++) {
dp[j]=min(dp[j],dp[j-w]+v);
if(j>=t) ans=min(ans,dp[j]);
}
}
cout<<ans;
return 0;
}
T3-Talent Show
有
输入格式
n m
W1 W2...Wn
V1 V2...Vn
样例输入 #1
3 15
20 10 30
21 11 31
样例输出 #1
63
数据规模与约定
对于全部的测试点,保证:
Solution
本题的重点也是边界,本题的最优解并不存在上述结论。并且
此时我们就要重新构建状态:
我们依旧设
但是对于
因为重量必然是递增的。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,ma,w[N],v[N],dp[N];
int main() {
cin>>n>>ma;
for(int i=1;i<=n;i++) cin>>w[i];
for(int i=1;i<=n;i++) cin>>v[i];
for(int i=1;i<=n;i++) {
for(int j=ma;j>=0;j--) {
dp[min(j+w[i],ma)]=max(dp[min(j+w[i],ma)],dp[j]+v[i]);
}
}
cout<<dp[ma];
return 0;
}
T4-得分
题目描述
现在 zql 手上有
对于
输入样例:
3 12
3 6
7 5
4 2
输出样例:
117
Solution
在题目中,做题的顺序,即剩下的时间与权值是有关系的。所以要考虑一个顺序,使得最优解存在于该顺序中。
假设现在有第
-
先
: -
先
:
得到排序顺序:
然后就是 01 背包的模板了。对第
Code
#include<bits/stdc++.h>
#define w(i) w[mp[i]]
#define v(i) v[mp[i]]
using namespace std;
const int N = 1e5+10;
int n,m,w[N],v[N],mp[N],ans;
int dp[N];//最多剩余 j 时间
int main() {
cin>>n>>m;
for(int i=1;i<=n;i++) {
cin>>w[i]>>v[i];
mp[i]=i;
}
sort(mp+1,mp+n+1,[](int a,int b) {
return w[a]*v[b]<w[b]*v[a];
});
for(int i=1;i<=n;i++) {
for(int j=0;j+w(i)<=m;j++) {
dp[j]=max(dp[j],dp[j+w(i)]+(j+w(i))*v(i));
ans=max(dp[j],ans);//剩余多少时间都可以统计答案
}
}
cout<<ans;
return 0;
}
T5-多人背包
题目描述
求01背包前k优解的价值和
DD 和好朋友们要去爬山啦!
他们一共有
在 DD 看来,合理的背包安排方案是这样的: 每个人背包里装的物品的总体积恰等于包的容量。 每个包里的每种物品最多只有一件,但两个不同的包中可以存在相同的物品。
任意两个人,他们包里的物品清单不能完全相同。 在满足以上要求的前提下,所有包里的所有物品的总价值最大是多少呢?
输入格式
第一行三个数
接下来每行两个数,表示体积和价值
输出格式
前
样例输入
2 10 5
3 12
7 20
2 4
5 6
1 1
样例输出
57
提示
对于
本题是一道经典的求背包
我们定义
对于每个
对于第
但是还需要排序。考虑优化。
就像归并排序一样,有两个有序的序列,使用两个指针,就可以合并为一个有序的序列。
至此,我们就解决了背包中的
Code
#include<bits/stdc++.h>
using namespace std;
int K,ma,n,dp[5001][51],w,v,t[51],ans;
int main() {
cin>>K>>ma>>n;
memset(dp,-0x3f,sizeof dp);
dp[0][1]=0;
for(int i=1;i<=n;i++) {
cin>>w>>v;
for(int j=ma;j>=w;j--) {
int l1=1,l2=1;
for(int p=1;p<=K;p++)
if(dp[j][l1]>dp[j-w][l2]+v)
t[p]=dp[j][l1++];
else
t[p]=dp[j-w][l2++]+v;
for(int p=1;p<=K;p++) dp[j][p]=t[p];
//要建立一个临时数组 t,如果随用随改的话可能就会重复计算
}
}
for(int i=1;i<=K;i++) ans+=dp[ma][i];
cout<<ans;
return 0;
}
T6-Bank notes
多重背包二进制优化可以通过本题。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n,m,c;
int w[N],tt[N],v[N],dp[N];
void add(int _w,int _v,int _c) {
int cnt=1;
while(_c) {
if(_c<cnt) cnt=_c;
// cout<<cnt<<" "<<cnt*_w<<" "<<cnt*_v<<"\n";
_c-=cnt,w[++c]=cnt*_w,v[c]=cnt*_v;cnt<<=1;
}
}
int main() {
cin>>n;
for(int i=1;i<=n;i++) cin>>tt[i];
for(int i=1,t;i<=n;i++) cin>>t,add(tt[i],1,t);
memset(dp,0x3f,sizeof dp);dp[0]=0;
cin>>m;
for(int i=1;i<=c;i++) {
for(int j=m;j>=w[i];j--) {
dp[j]=min(dp[j],dp[j-w[i]]+v[i]);
}
}
cout<<dp[m];
return 0;
}
T7-剪草
有
- 每棵小草都长高了,第
棵小草长高的高度是 。 - 选中一棵小草并将高度变为
,它在下一秒还会生长。 - 计算这
棵草的高度和,如果不超过 ,则完成任务,否则轮到下一时刻。
问最早在什么时候可以完成任务。如果永远完不成,输出
输入格式
N H
h1 h2...hn
g1 g2...gn
输出格式
最早的完成时刻。
数据范围
输入样例
3 16
5 8 58
2 1 1
输出样例
1
Solution
这题的背包也和贪心结合了起来。
与 T5 一样,选择的次序也会对结果产生影响。先来考虑顺序。有
- 先
: - 先
:
消去相同部分,想要高度和更大,就要使
排序后,进行背包。设
Code
#include<bits/stdc++.h>
#define h(i) h[mp[i]]
#define g(i) g[mp[i]]
using namespace std;
const int N = 1e5+10;
int n,s,s1,s2,h[N],g[N],mp[N],dp[N];
//第 j 时刻减的最多草
int main() {
cin>>n>>s;
for(int i=1;i<=n;i++)
cin>>h[i],s1+=h[i],mp[i]=i;
for(int i=1;i<=n;i++)
cin>>g[i],s2+=g[i];
sort(mp+1,mp+n+1,[](int a,int b) {
return g[a]<g[b];
});
for(int i=1;i<=n;i++) {
for(int j=i;j>0;j--) {
dp[j]=max(dp[j],dp[j-1]+h(i)+j*g(i));//j 不剪或剪
}
}
for(int i=0;i<=n;i++)//在第 i 个时刻,判断总共的高度减去剪掉的高度满足条件与否
if(s1+s2*i-dp[i]<=s) return 0&(printf("%d",i));
cout<<-1;
return 0;
}
T8-[TJOI2013] 黄金矿工
题目描述
小 A 最近迷上了在上课时玩《黄金矿工》这款游戏。为了避免被老师发现,他必须小心翼翼,因此他总是输。
在输掉自己所有的金币后,他向你求助。每个黄金可以看做一个点(没有体积)。现在给出你
请你帮助小 A 算出在时间
输入格式
第一行两个整数
接下来
输出格式
一个整数,表示你可以在
样例 #1
样例输入 #1
3 10
1 1 1 1
2 2 2 2
1 3 15 9
样例输出 #1
3
样例 #2
样例输入 #2
3 10
1 1 13 1
2 2 2 2
1 3 4 7
样例输出 #2
7
提示
- 对于
的数据, ; - 对于
的数据, , 。
保证
Solution
这题关键在于将坐标系中的值,转变为背包问题的模型。我们可以枚举一个开始点,然后往后找在一条直线的点。
此时要考虑如何做到按顺序取,可以令每一条直线为一组,从起点开始做一个前缀和,然后分组背包,意义在于可以实现按顺序取。
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 201,M = 4e4+10;
int n,m,ti,tj,x,y,c;
int mp[N<<1][N],mpp[N<<1][N],w[N][N],v[N][N],cn,cy[N],dp[M];
int main() {
cin>>n>>m;
for(int i=1,d;i<=n;i++) {
cin>>x>>y>>c>>d;
x+=200;//x有负数 防越界
mp[x][y]=d;
mpp[x][y]=c;
}
for(int i=-200,p=i+200;i<=200;i++,p++) for(int j=0;j<=200;j++)
if(mp[p][j]) {
++cn,cy[cn]=1;
w[cn][1]=mp[p][j];
v[cn][1]=mpp[p][j];//更新价值
mp[p][j]=0;
for(int i2=i,p2=p;i2<=200;i2++,p2++) for(int j2=j;j2<=200;j2++)
if(i*j2==j*i2&&abs(j)<abs(j2)&&mp[p2][j2]) {
++cy[cn];
w[cn][cy[cn]]=w[cn][cy[cn]-1]+mp[p2][j2];
v[cn][cy[cn]]=v[cn][cy[cn]-1]+mpp[p2][j2];//前缀和
mp[p2][j2]=0;//当前点已选
j2=200;//只能是斜着的,所以直线搜索不可能有符合条件的点
}
}
for(int i=1;i<=cn;i++)
for(int j=m;j>=0;j--)
for(int k=1;k<=cy[i];k++)
if(j>=v[i][k])//分组背包
dp[j]=max(dp[j],dp[j-v[i][k]]+w[i][k]);
cout<<dp[m];
return 0;
}
T9-P2967
本文作者:cjrqwq
本文链接:https://www.cnblogs.com/yfzqwq/p/18492811
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现