【问题描述】
小沐同学确信所有问题都有个多项式时间算法,为了证明,他决定自己去当一次旅行商,在上路之前,小 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;
这道题是个大杂烩,融合了几个背包问题,分析状态转移方程时需要分情况讨论。先设f(i,j)为前i个物品选择一些使得体积为j的最大价值。题目给了三类物品,第一类的方程是f(i,j)=max{f(i-1,j),f(i-1)(j-k)+k*k*a-k*b) | 1<=k<=j} ,第二类的方程是f(i,j)=max{f(i-1,j),f(i-1)(j-k*c[j])+k*v[i]) | 0<=k<=min(j/c[j],c)}, 第三类的方程是f(i,j)=max{f(i-1,j),f(i-1)(j-k*c[j])+k*v[i] | 0<=k<=j/c[j]}。边界是f(0,j)=-inf(选0个物体时体积不可能大于0)和f(i,0)=0(选i个物体时体积等于0时价值为0),然后用填表法实现就可以了。最后答案就是f(n,m)。可以用一维滚动数组优化(第一,二类要倒着填)。
我实现方程的时候把循环j的语句直接放在循环i语句后判断语句前,错了。
后来我把循环j的语句拆分放到每一类里,对了。
不懂。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int inf=1000000000;
int n,m,d[202][2003],s[202];
bool vis[202];
//f(i,j)前i个物品选择一些使得体积为j的最大价值
//若i是jia f(i,j)=max(f(i-1,j),f(i-1)(j-k)+k*k*a-k*b) 1<=k<=j
//若i是yi f(i,j)=max(f(i-1,j),f(i-1)(j-k*c[j])+k*v[i]) 0<=k<=min(j/c[j],c)
//若i是bing f(i,j)=max(f(i-1,j),f(i-1)(j-k*c[j])+k*v[i]) 0<=k<=j/c[j]
struct jia
{
int a,b;
};
jia x[602];
struct yi
{
int v,c,w;
};
yi y[602];
struct bing
{
int v,c;
};
bing z[602];
int main()
{
//freopen("select.in","r",stdin);
//freopen("select.out","w",stdout);
scanf("%d%d",&n,&m);
int a,b,v,w,c;
for(int i=1;i<=n;i++)
{
int t;
scanf("%d",&t);
s[i]=t;
if(t==1)
{
scanf("%d %d",&a,&b);
x[i].a=a;
x[i].b=b;
}
if(t==2)
{
scanf("%d %d %d",&v,&c,&w);
y[i].v=v;
y[i].c=c;
y[i].w=w;
}
if(t==3)
{
scanf("%d %d",&v,&c);
z[i].v=v;
z[i].c=c;
}
}
for(int i=0;i<=n;i++) d[i][0]=0;
for(int i=1;i<=m;i++) d[0][i]=-inf;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(s[i]==1)
{
int t=-inf;
for(int j=0;j<=m;j++)
{
for(int k=0;k<=j;k++)
{
if(t<=d[i-1][j-k]+k*k*x[i].a-k*x[i].b)
t=d[i-1][j-k]+k*k*x[i].a-k*x[i].b;
}
d[i][j]=t;
}
}
if(s[i]==2)
{
for(int j=y[i].c;j<=m;j++)
{
int t=-inf;
for(int k=0;k<=y[i].w&&k*y[i].c<=j;k++)
{
t=max(t,d[i-1][j-k*y[i].c]+k*y[i].v);
}
d[i][j]=t;
}
}
if(s[i]==3)
{
int t=-inf;
for(int j=z[i].c;j<=m;j++)
{
for(int k=0;z[i].c*k<=j;k++)
{
t=max(t,d[i-1][j-k*z[i].c]+k*z[i].v);
}
d[i][j]=t;
}
}
}
printf("%d\n",d[n][m]);
return 0;
}