【复赛模拟试题】 物品选取

【问题描述】

  小沐同学确信所有问题都有个多项式时间算法,为了证明,他决定自己去当一次旅行商,在上路之前,小 X 需要挑选一些在路上使用的物品,但他只有一个 能装体积为 m 的背包。显然,背包问题对小沐来说过于简单了,所以他希望你来帮他解决这个问题。

  小沐可以选择的物品有 n样,一共分为甲乙丙三类:
  1.甲类物品的价值随着你分配给他的背包体积变化,它的价值与分配给它的体积满足函数关系式,v(x) = A*x^2-B*x,x表示分配给该物品的体积,为非负整数,A,B是每个甲类物品的两个参数。注意每个体积的甲类物品只有一个。
  2.乙类物品的价值 A和体积 B都是固定的,但是每个乙类物品都有个参数C,表示这个物品可供选择的个数。
  3.丙类物品的价值 A和体积 B也是固定的,但是每个丙类物品可供选择的个数都是无限多个。

  你最终的任务是确定小沐的背包最多能装有多大的价值上路。

【输入格式】

  第一行两个整数 n,m,表示背包物品的个数和背包的体积;
  接下来 n行,每行描述一个物品的信息。第一个整数 x,表示物品的种类:
  若 x 为1表示甲类物品,接下来两个整数 A,B,为A类物品的两个参数;
  若 x 为2表示乙类物品,接下来三个整数 A,B,C。A表示物品的价值,B表示它的体积,C 表示它的个数;
  若 x 为3表示丙类物品,接下来两个整数A,B。A表示它的价值,B表示它的体积。

【输出格式】

  仅一行为一个整数,表示小 X的背包能装的最大价值。

【输入样例】

【样例1】
 1 0
 1 1 1

【样例2】
 4 10
 2 1 2 1
 1 1 2
 3 5 2
 2 200 2 3

【输出样例】

【样例1】
 0

【样例2】
 610

【数据范围】

对于50%的数据,只有乙和丙两类物品;
对于70%的数据,1<=n<=100, 1<=m<=500,0<=A,B,C<=200;
对于100%的数据,1<=n<=100, 1<=m<=2000,0<=A,B,C<=200;

这道题是一个超级加强背包问题。这个问题要分3部分来思考(就是3种背包分开想),然后问题就简单了,重点就落在了第一种物品了,我这里采取的方法是直接暴力枚举:第j大的那种,然后枚举j。
详细代码如下:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=105;
struct shu
{
    long long id,A,B,C;
}a[maxn];

int n,m;
long long d[maxn][2005]={0};

int read()
{
    int x=0;
    char ch;
    ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch<='9'&&ch>='0')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}
void init()
{
    n=read();
    m=read();
    for(int i=1;i<=n;i++)
    {
        a[i].id=read();
        if(a[i].id==1)
        {
            a[i].A=read();
            a[i].B=read();
        }
        if(a[i].id==2)
        {
            a[i].A=read();
            a[i].B=read();
            a[i].C=read();
        }
        if(a[i].id==3)
        {
            a[i].A=read();
            a[i].B=read();
        }
    }
}
int main()
{
    //freopen("select.in","r",stdin);
    //freopen("select.out","w",stdout);
    init();
    for(int i=1;i<=n;i++)
    {
        if(a[i].id==1)
        for(int k=0;k<=m;k++)
        {
            long long p=a[i].A*k*k-a[i].B*k;
            for(int j=m;j>=k;j--)
            {
                d[i][j]=max(d[i][j],d[i-1][j-k]+p);
            }
        }

        if(a[i].id==2)
        for(int j=m;j>=0;j--)
        for(int k=0;k<=a[i].C&&k*a[i].B<=j;k++)
        {
            long long t=d[i-1][j-k*a[i].B]+a[i].A*k;
            d[i][j]=max(d[i][j],t);
        }

        if(a[i].id==3)
        for(int j=0;j<=m;j++)
        {
            d[i][j]=max(d[i-1][j],d[i][j]);
            if(j>=a[i].B)
            d[i][j]=max(d[i][j],d[i][j-a[i].B]+a[i].A);
        }
    }
    cout<<d[n][m];
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值