背包系列

        庆功会(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]; 
} 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值