背包
(一)01背包
洛谷P1049 [NOIP 2001 普及组] 装箱问题:
https://www.luogu.com.cn/problem/P1049
题目描述
有一个箱子容量为 V,同时有 n 个物品,每个物品有一个体积。
现在从 n 个物品中,任取若干个装入箱内(也可以不取),使箱子的剩余空间最小。输出这个最小值。
输入格式
第一行共一个整数 V,表示箱子容量。
第二行共一个整数 n,表示物品总数。
接下来 n 行,每行有一个正整数,表示第 i 个物品的体积。
输出格式
共一行一个整数,表示箱子最小剩余空间。
代码实现:
1. 二维
#include "bits/stdc++.h"
using namespace std;
int x,f[32][20010];
int main(){
int n,m;
cin>>m>>n;
for(int i=1;i<=n;i++){
cin>>x;
for(int j=0;j<=m;j++)
f[i][j]=f[i-1][j];
for(int j=x;j<=m;j++)
f[i][j]=max(f[i-1][j],f[i-1][j-x]+x);
}
cout<<m-f[n][m];
return 0;
}
2. 一维
#include "bits/stdc++.h"
using namespace std;
int x,f[20010];
int main(){
int n,m;
cin>>m>>n;
for(int i=1;i<=n;i++){
cin>>x;
for(int j=m;j>=x;j--)
f[j]=max(f[j],f[j-x]+x);
//注意j从后往前循环,因为f具有后效性
}
cout<<m-f[m];
return 0;
}
(二)完全背包
洛谷P1616 疯狂的采药:
https://www.luogu.com.cn/problem/P1616
题目描述
LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是 LiYuxiang,你能完成这个任务吗?
此题和原题的不同点:
-
每种草药可以无限制地疯狂采摘。
-
药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!
输入格式
输入第一行有两个整数,分别代表总共能够用来采药的时间 t 和代表山洞里的草药的数目 m。
第 2 到第 (m+1) 行,每行两个整数,第 (i+1) 行的整数 ai,bi 分别表示采摘第 i 种草药的时间和该草药的价值。
输出格式
输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
1. 二维
#include "bits/stdc++.h"
#define ll long long
using namespace std;
const int T=1e7+5,M=1e4+5;
ll t,m,a[M],b[M],f[T][T];
int main(){
cin>>t>>m;
for(int i=1;i<=m;i++){
cin>>a[i]>>b[i];
for(int j=a[i];j<=t;j++)
f[i][j]=max(f[i-1][j],f[i-1][j-a[i]]+b[i]);
}
cout<<f[t];
return 0;
}
2. 一维
#include "bits/stdc++.h"
#define ll long long
using namespace std;
const int T=1e7+5,M=1e4+5;
ll t,m,a[M],b[M],f[T];
int main(){
cin>>t>>m;
for(int i=1;i<=m;i++){
cin>>a[i]>>b[i];
for(int j=a[i];j<=t;j++)
f[j]=max(f[j],f[j-a[i]]+b[i]);
}
cout<<f[t];
return 0;
}
(三)二进制优化
以完全背包为例:洛谷P1776宝物筛选:
https://www.luogu.com.cn/problem/P1776
题目描述
终于,破解了千年的难题。小 FF 找到了王室的宝物室,里面堆满了无数价值连城的宝物。
这下小 FF 可发财了,嘎嘎。但是这里的宝物实在是太多了,小 FF 的采集车似乎装不下那么多宝物。看来小 FF 只能含泪舍弃其中的一部分宝物了。
小 FF 对洞穴里的宝物进行了整理,他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值,之后开始了宝物筛选工作:小 FF 有一个最大载重为 W 的采集车,洞穴里总共有 n 种宝物,每种宝物的价值为 vi,重量为 wi,每种宝物有 mi 件。小 FF 希望在采集车不超载的前提下,选择一些宝物装进采集车,使得它们的价值和最大。
输入格式
第一行为两个整数 n 和 W,分别表示宝物种数和采集车的最大载重。
接下来 n 行每行三个整数 vi,wi,mi。
输出格式
输出仅一个整数,表示在采集车不超载的情况下收集的宝物的最大价值。
代码实现:
1. 一维二进制优化
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int n,m,x,y,z,cnt,f[N],w[N],v[N];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&x,&y,&z);
for(int j=1;j<=z;j<<=1)v[++cnt]=x*j,w[cnt]=y*j,z-=j;
if(z)v[++cnt]=x*z,w[cnt]=y*z;//差值
}
for(int i=1;i<=cnt;i++)
for(int j=m;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+v[i]);
printf("%d\n",f[m]);
return 0;
}
浙公网安备 33010602011771号