在《Harry Potter and the Deathly Hallows》中,Harry Potter他们一起逃亡,现在有许多的东西要放到赫敏的包里面,但是包的大小有限,所以我们只能够在里面放入非常重要的物品,现在给出该种物品的数量、体积、价值的数值,希望你能够算出怎样能使背包的价值最大的组合方式,并且输出这个数值,赫敏会非常地感谢你。
【输入文件】(hallows.in)
(1)第一行有2个整数,物品种数n和背包装载体积v。
(2)2行到i+1行每行3个整数,为第i种物品的数量m、体积w、价值s。.
【输出文件】(hallows.out)
输出文件hallows.out仅包含一个整数,即为能拿到的最大的物品价值总和。
【输入样例】
2 10
3 4 3
2 2 5
【输出样例】
13
【注释】
选第一种一个,第二种两个。
结果为3*1+5*2=13
【数据规模】
对于30%的数据
1<=v<=500
1<=n<=2000
1<=m<=10
1<=w<=20
1<=s<=100
对于100%的数据
1<=v<=500
1<=n<=2000
1<=m<=5000
1<=w<=20
1<=s<=100
#include<iostream>
#include<cstdio>
using namespace std;
int q,dp[510],x,y,z,n,s=0;
void ddp(int xx,int yy)//即时背包
{
for(int i=n;i>=xx;i--)dp[i]=max(dp[i],dp[i-xx]+yy);
return;
}
int main()
{
scanf("%d%d",&q,&n);
while(q--)
{
scanf("%d%d%d",&x,&y,&z);
s=1;//位的价值
while(x>=s)//二进制拆分
{
ddp(s*y,s*z);
x-=s;
s*=2;
}
if(x!=0)ddp(x*y,x*z);
}
printf("%d",dp[n]);
return 0;
}
这道题是一个有限背包,我们可以按照有限背包的板子写:
#include<bits/stdc++.h>
using namespace std;
int n,v;
struct bag {
int m,w,s;
} a[1000001];
int dp[1000001];
int main() {
scanf("%d %d" ,&n ,&v);
for(int i = 1; i <= n; i++) {
scanf("%d %d %d" ,&a[i].m,&a[i].w,&a[i].s);
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= a[i].m; j++) {
for(int k = v; k >= a[i].w; k--) {
dp[k] = max(dp[k],dp[k - a[i].w] + a[i].s);
}
}
}
printf("%d" ,dp[v]);
return 0;
}
但是这样做复杂度是有亿点点高的,高到可以卡掉三个点,所以我们需要用到二进制优化来帮我们降低复杂度:
什么是二进制优化呢?
顾名思义,我们把同种每2n的物品放在一起,当作一件物品(其价值和体积需要对应累加),处理完后当作0 1背包来做即可。
比如7个物品:
7 = 1 + 2 + 4.
而有意思的是,1,2,4正好可以凑出从1到7所有的整数,因此我们这么做在dp的时候是不会少情况的(具体证明我也不会)。
接下来就是二进制优化之后的代码:
#include<bits/stdc++.h>
using namespace std;
int ans = 0,nn = 0,t;
int dp[2001]= { },j,w[100001],s[100001];
int a[100001],b[1000001];
int m[100001];
int n,v;
int cnt = 0;
int main() {
scanf("%d %d" ,&n,&v);
for(int i = 1;i <= n; i++){
scanf("%d %d %d" ,&m[i],&a[i],&b[i]);
}
for(int i = 1;i <= n; i++){
for(int j = 1;j <= m[i];j<<=1){
w[++cnt] = j * a[i];
s[cnt] = j * b[i];
m[i] = m[i] - j;
}
if(m[i] > 0){
s[++cnt] = m[i] * b[i];
w[cnt] = m[i] * a[i];
}
}
for(int i = 1; i <= cnt; i++) {
for(int k = v; k >= w[i]; k--) {
dp[k] = max(dp[k],dp[k - w[i]] + s[i]); //处理完后所有的都要换成新数组
}
}
printf("%d" ,dp[v]);
return 0;
}