ybt1269_庆功会
时空限制 1000ms/64MB
【题目描述】
为了庆贺班级在校运动会上取得全校第一名成绩,班主任决定开一场庆功会,为此拨款购买奖品犒劳运动员。期望拨款金额能购买最大价值的奖品,可以补充他们的精力和体力。
【输入】
第一行二个数n(n≤500),m(m≤6000),其中n代表希望购买的奖品的种数,m表示拨款金额。
接下来n行,每行3个数,v、w、s,分别表示第I种奖品的价格、价值(价格与价值是不同的概念)和能购买的最大数量(买0件到s件均可),其中v≤100,w≤1000,s≤10。
【输出】
一行:一个数,表示此次购买能获得的最大的价值(注意!不是价格)。
【输入样例】
5 1000
80 20 4
40 50 9
30 50 7
40 30 6
20 20 1
【输出样例】
1040
代码
法一:多重背包朴素算法
#include<iostream> //朴素算法
#include<algorithm>
using namespace std;
int f[6005];
int main(){
int n,m;
cin>>n>>m;
for (int i=1,v,w,s; i<=n; i++){
cin>>v>>w>>s;
for (int j=m; j>=v; j--) //转换为01背包模式
for (int k=0; k<=s; k++)
if (j-k*v>=0) f[j]=max(f[j],f[j-k*v]+k*w);
else break;
}
cout<<f[m]<<endl;
return 0;
}
法二:二进制优化
#include<iostream> //优化算法
#include<algorithm>
using namespace std;
const int N = 10005;
int f[6005],price[N],value[N];
int main(){
int n,m,k=0;
cin>>n>>m;
for (int i=1,v,w,s; i<=n; i++){
cin>>v>>w>>s;
for (int j=1; j<=s; j*=2){ //用二进制形式存储所有物品价格和价值
price[++k]=j*v;
value[k]=j*w;
s-=j;
}
if (s>0) price[++k]=s*v,value[k]=s*w;
}
for (int i=1; i<=k; i++) //01背包求解
for (int j=m; j>=price[i]; j--)
f[j]=max(f[j],f[j-price[i]]+value[i]);
cout<<f[m]<<endl;
return 0;
}