庆功会(ssl 2289)
Description
为了庆贺班级在校运动会上取得第一名的成绩,班主任决定开一场庆功会,为此拔款购买奖品奖励运动员,期望拔款金额能购买最大价值的奖品,可以补充他们的精力和体力。
Input
第一行二个数n(n<=500),m(m<=5000),其中n代表希望购买的物品的种数,m表示班会拨的钱数。
接下来n行,每行3个数,v、w、s,分别表示第I种物品的价格、价值(价格 与 价值 是不同的概念)和购买的数量(只能买0件或s件),其中v<=100,w<=1000,s<=10
Output
第一行:一个数,表示此次购买能获得的最大的价值(注意!不是价格)。
Sample Input
5 1000
80 20 4
40 50 9
30 50 7
20 20 1
Sample Output
1040
解题方法
01背包改一改就可以了。
代码
#include<iostream>
using namespace std;
int a[501],b[501],f[6001],m,n,j,s[501];
int main()
{ cin>>n>>m; for (int i=1;i<=n;i++) { cin>>a[i]>>b[i]>>s[i];} for (int i=1;i<=n;i++) for (int c=m;c>=a[i];c--) for(int k=0;k<=s[i];k++)//循环种数 { if (c-a[i]*k<0) break; //判断有没有越界 f[c]=max(f[c],f[c-a[i]*k]+b[i]*k); //c不变,代价和价值乘种数 } cout<<f[m];
}
二进制优化
#include<iostream>
using namespace std;
int f[6001],a[1001],b[1001],n,m,u;
int main()
{ cin>>n>>m; for (int i=1;i<=n;i++) { int x,y,s,t=1; cin>>x>>y>>s; while (s>t) { a[++u]=x*t;//分成不同数量的物品,并保证可以合成最大数以下的任意一个数 b[u]=y*t; s=s-t; t=t*2; } a[++u]=x*s;//余数 b[u]=y*s; } for (int i=1;i<=u;i++) for (int j=m;j>=a[i];j--) f[j]=max(f[j],f[j-a[i]]+b[i]);//01背包 cout<<f[m];
}
混合背包(ssl 2301)
Description
背包体积为V ,给出N个物品,每个物品占用体积为Vi,价值为Wi,每个物品要么至多取1件,要么至多取mi件(mi > 1) , 要么数量无限 , 在所装物品总体积不超过V的前提下所装物品的价值的和的最大值是多少?
Input
第一行两个数V,N下面N行每行三个数Vi,Wi,Mi表示每个物品的体积,价值与数量,Mi=1表示至多取一件,Mi>1表示至多取Mi件,Mi=0表示数量无限
Output
1个数Ans表示所装物品价值的最大值
Sample Input
10 3
2 1 0
3 3 1
4 5 4
Sample Output
11
解题方法
在循环里加一个判断,是0用完全背包,不是0用多重背包。
代码
#include<iostream>
using namespace std;
int a[501],b[501],f[6001],m,n,j,s[501];
int main()
{
cin>>m>>n;
for (int i=1;i<=n;i++){cin>>a[i]>>b[i]>>s[i];}
for (int i=1;i<=n;i++)if (s[i]==0)//判断是多重背包还是完全背包for (int c=a[i];c<=m;c++)//完全背包f[c]=max(f[c],f[c-a[i]]+b[i]); else for (int c=m;c>=a[i];c--)//多重背包for(int k=0;k<=s[i];k++){if (c-a[i]*k<0) break;//判断有没有越界 f[c]=max(f[c],f[c-a[i]*k]+b[i]*k); }
cout<<f[m];
}
分组背包(ssl 2291)
Description
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
Input
第一行:三个整数,v(背包容量,v<=200),n(物品数量,n<=30)和t(最大组号,t<=10);
第2..n+1行:每行三个整数wi,ci,p,表示每个物品的重量、价值、所属组号。
Output
仅一行,一个数,表示最大总价值。
Sample Input
10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3
Sample Output
20
解题方法
把同组的放在一个数组里,再加多一个循环就可以了。
代码
#include<iostream>
using namespace std;
int v,y,u,a[300][300],b[300][300],f[1000],p[11],m,n,t;
int main()
{
for (int i=1;i<=10;i++)p[i]=0;
cin>>m>>n>>t;
for (int i=1;i<=n;i++){cin>>v>>y>>u;a[u][++p[u]]=v;//p[u]用于放第u组有多少个物品b[u][p[u]]=y;//第u组第p[u]个的价格和价值}
for (int i=1;i<=t;i++)//第几组for (int j=m;j>=0;j--)for (int c=1;c<=p[u];c++)//第几个if (j>=a[i][c])//判断有没有越界f[j]=max(f[j],f[j-a[i][c]]+b[i][c]);
cout<<f[m];
}
货币系统(ssl 1115)
Description
母牛们不但创建了他们自己的政府而且选择了建立了自己的货币系统。
[In their own rebellious way],他们对货币的数值感到好奇。
传统地,一个货币系统是由1,5,10,20 或 25,50, 和 100的单位面值组成的。
母牛想知道有多少种不同的方法来用货币系统中的货币来构造一个确定的数值。
举例来说, 使用一个货币系统 {1,2,5,10,...}产生 18单位面值的一些可能的方法是:18x1, 9x2, 8x2+2x1, 3x5+2+1,等等其它。
写一个程序来计算有多少种方法用给定的货币系统来构造一定数量的面值。
保证总数将会适合long long (C/C++) 和 Int64 (Free Pascal)。
Input
货币系统中货币的种类数目是 V 。 (1<= V<=25)
要构造的数量钱是 N 。 (1<= N<=10,000)
第 1 行: 二整数, V 和 N
第 2 ..V+1行: 可用的货币 V 个整数 (每行一个 每行没有其它的数)。
Output
单独的一行包含那个可能的构造的方案数。
末尾有空行
Sample Input
3 10
1 2 5
Sample Output
10
解题方法
累加之前的组数就可以了。
代码
#include<iostream>
using namespace std;
int m,n,a[30];
long long f[10100];
int main()
{ cin>>m>>n; for (int i=1;i<=m;i++) cin>>a[i]; f[0]=1;//预处理 for (int i=1;i<=m;i++) for (int j=a[i];j<=n;j++) f[j]=f[j]+f[j-a[i]];//用a[i]的钱时等于其他钱组成的种数加上用a[i]之前的种数 cout<<f[n];
}