Problem Description
为了庆贺班级在校运动会上取得全校第一名成绩,班主任决定开一场庆功会,为此拨款购买奖品犒劳运动员。期望拨款金额能购买最大价值的奖品,可以补充他们的精力和体力。
Input
输入第一行为T,表示数据组数,对于每组数据的第一行二个数n(n<=500),m(m<=6000),其中n代表希望购买的奖品的种数,m表示拨款金额。
接下来n行,每行3个数,v、w、s,分别表示第I种奖品的价格、价值(价格与价值是不同的概念)和购买的数量(买0件到s件均可),其中v<=100,w<=1000,s<=10。
接下来n行,每行3个数,v、w、s,分别表示第I种奖品的价格、价值(价格与价值是不同的概念)和购买的数量(买0件到s件均可),其中v<=100,w<=1000,s<=10。
Output
对于每组数据输出一个数,表示此次购买能获得的最大的价值(注意!不是价格)。
Sample Input
1 5 1000 80 20 4 40 50 9 30 50 7 40 30 6 20 20 1
Sample Output
1040【解析】和01差不多 区别在于 每个物品的数量是有限的(或者说是给定的) 每一种物品假设有n[i]件,那么这个物品的决策就是n[i]+1(为什么要加1呢,因为还可以不取这件物品,也算一种决策方式)下面的代码是两种方法 第二种为 二进制优化 理解一下【代码】和01很像,只是1件物品改成的有限件 只需要加一个循环 枚举到底选几件好了
#include<iostream> #include<cstdio> using namespace std; int pri[10000],val[2000],cnt[2000],f[2000]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d%d%d",&pri[i],&val[i],&cnt[i]); } for(int i=1;i<=n;i++) { for(int j=m;j>=0;j--) { for(int k=0;k<=cnt[i];k++) { if(j-k*pri[i]<0)break; f[j]=max(f[j],f[j-k*pri[i]]+k*val[i]); } } } printf("%d",f[m]); return 0; }
【二进制优化】
#include<iostream> #include<cstdio> using namespace std; int w[2000],v[2000],c[20000],f[20000],V[2000],W[2000]; int main() { int n,m,cnt=0; scanf("%d%d",&n,&m); for(int i=0;i<n;i++) { scanf("%d%d%d",&w[i],&v[i],&c[i]);//价格,价值,数量; for(int j=1;j<=c[i];j<<=1)//j<<=1为j=j*2; ------------*(1) { V[cnt]=j*v[i];//cnt为情况数目,j为取得件数 //为i物品取j件时总价值 W[cnt++]=j*w[i]; // printf("%d %d %d %d\n",W[cnt-1],V[cnt-1],c[i],j);*(3) c[i]-=j;//看下面的数据理解 这里是二进制的分解 } if(c[i]>0)//如果没有分解完-----------*(2) { V[cnt]=c[i]*v[i]; W[cnt++]=c[i]*w[i]; // printf("%d %d %d %d\n",i,c[i],V[cnt-1],W[cnt-1]); } } for(int i=0;i<cnt;i++) { for(int j=m;j>=W[i];j--) { f[j]=max(f[j],f[j-W[i]]+V[i]); } } printf("%d",f[m]); return 0; }
解释一下*所在的位置
*(1)任何一个数 都可以被分解为 2的n次方的形式
如 1 2 4 8 16.。。。为2的n的次方前几项
则 7=1+2+4. 6=4+2;
所以我们将第i件物品的个数进行分解为2的n次方的和的形式。
*(2)当你分解的个数没有分解完时,
如 (按照程序分解)11=1+2+4;(这里的意思为 11在程序中分解成了 1 2 4)尽管1 2 4这三个数可以 1 2 4 4来组成11;
可是程序中只保存了 取1个时 取2个时 取4个时,当我们既取1个又取2个,4个 可是没办法取11个全部;
//具体详细的证明为什么任何数都可以分解成2的n次方就不证了(因为我不会证orz)
给上面代码的数组加深理解 是怎样分解的呢
*(3)
5 1000 80 20 4 80 20 4 1 160 40 3 2 40 50 9 40 50 9 1 80 100 8 2 160 200 6 4 30 50 7 30 50 7 1 60 100 6 2 120 200 4 4 40 30 6 40 30 6 1 80 60 5 2 20 20 1 20 20 1 1 1040
注意看最后一个数为分解的件数 都为2的n次方
来源:https://www.cnblogs.com/zzyh/p/6741029.html