您的位置:首页 > 编程语言 > C语言/C++

【codevs5226】物品选取

2016-08-06 13:33 176 查看
【问题描述】
  
   小沐同学确信所有问题都有个多项式时间算法,为了证明,他决定自己去当一次旅行商,在上路之前,小 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;
题目大意:有三种物品,每种物品有着自己不同的属性,现在求在最后装载的总体积小于等于m的前提下,背包内物品的最大价值。这类背包问题关心的是"选不选"这个问题。是标准的0/1背包。

算法:动态规划O(n*m^2)

设状态函数f(j)表示在前i个物品中选择一些装入背包,在背包内物品体积和不超过j的前提下,背包内物品价值的最大值。

先考虑较为简单的乙类和丙类物品,对于乙类物品i,每一次都可以选0件,选1件...直到选min(a[i].C,j/a[i].B)件。对应状态f(j-a[i].B)+a[i].A,f(j-2*a[i].B)+2*a[i].A...f(j-min(j/a[i].B,a[i].C)

而丙类物品和乙类物品类似,只是没有a[i].c的限制。

现在考虑最难的甲类物品,甲类物品的价值随着指定体积的大小而变化。而当前可指定给甲物品的体积为0(不放)、1......、j

对应状态f(j)、f(j-1)+A*1^2+B*1、.......、f(0)+A*j^2+B*j。

在三类物品的所有状态中,取一个最大的价值,就是所求的f(i,j)

代码实现时注意解这种物品种类和属性较多的题,要注意分类处理,每考虑一个物品,都应该取循环一次j。

最后的答案f(m)

边界 f(0)=0(不能放任何物品)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<algorithm>
#define maxn 105
#define maxm 2005
using namespace std;
typedef long long LL;
int n,m;
struct data
{
int A,B,C,x;
}a[maxn];
LL f[maxm];
int main()
{
//freopen("select.in","r",stdin);
//freopen("select.out","w",stdout);

scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(x==1)
{
int A,B;
scanf("%d%d",&A,&B);
a[i]=(data){A,B,1,x};
}

if(x==2)
{
int A,B,C;
scanf("%d%d%d",&A,&B,&C);
a[i]=(data){A,B,C,x};
}

if(x==3)
{
int A,B;
scanf("%d%d",&A,&B);
a[i]=(data){A,B,2005,x};
}

}

f[0]=0;

for(int i=1;i<=n;i++)
{
if(a[i].x==1)
{
for(int j=m;j>=0;j--)
for(int x=j;x>=1;x--)
f[j]=max(f[j],f[j-x]+a[i].A*x*x-a[i].B*x);
}

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

if(a[i].x==3)
{
for(int j=a[i].B;j<=m;j++)
f[j]=max(f[j],f[j-a[i].B]+a[i].A);
}

}

cout<<f[m]<<'\n';

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息