11083 旅游背包(优先做)
时间限制:10000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: G++;GCC;VC;JAVA
Description
想去旅游吗?那得先准备背包!
背包用来装旅游物品,现在共n种(n<=50)旅游物品,每种物品都有体积vi,重量wi,数量ci,价值ti
(vi,wi,ci和ti都为整数)。
限制体积最多V立方厘米(V<=1000),重量最多W公斤(W<=500)。
请问你如何选择物品,使得带上的物品总价值最大,这个最大总价值为多少?
比如:
物品 体积 重量 数量 价值
编号 (立方厘米) (公斤) (个) (元)
1 30 3 10 4
2 50 8 10 5
3 10 2 10 2
4 23 5 8 3
5 130 20 5 11
若V为500,W为100,则选择物品的最大价值为72(且72=104+102+4*3:由10件物品1,10件物品3,
和4件物品4组成)。
这是一个多维且有界的背包问题,属于常规0-1背包问题的扩展问题。
输入格式
第一行,物品的种类n,背包体积的限制V,背包载重量的限制W。n,V和W的范围如前所述。
接下来n行,每行为该种物品i的体积vi,重量wi,数量ci,价值ti (规定vi,wi,ci和ti都为整数)。
输出格式
仅一行,为选择物品子集所能获得的最大价值。
输入样例
5 500 100
30 3 10 4
50 8 10 5
10 2 10 2
23 5 8 3
130 20 5 11
输出样例
72
提示
此为多维有界的背包问题。
n种物品,每种物品体积v[i],重量w[i],c[i]件,价值t[i]。
设f[i][x][y]表示:可选前i种物品,选出物品体积和不超过x,重量和不超过y的最大价值。
由于f[i][x][y]是一个比较大的空间,请不要在函数内部定义,放到函数外做全局变量来定义才可。
则三维数组f先全部初始化为0,f[i][x][y]递归关系如下:
if i=1 时,
f[1][x][y] = 0, if x/v[1]=0 || y/w[1]=0
f[1][x][y] = min(x/v[1], y/w[1], c[1]) * t[1], if x/v[1]>0 && y/w[1]>0
if i>1 && (x>=v[i] && y>=w[i]) 时,
令 k = min(c[i],x/v[i],y/w[i]),k表示以背包的体积和重量能放入的第i种物品最多的件数。
f[i][x][y] = max{f[i-1][x][y], f[i-1][x-kv[i]][y-kw[i]] + k*t[i] | for all possible k},
else if i>1 && (x<v[i] || y<w[i]) 时,
f[i][x][y] = f[i-1][x][y]
看公式会有点晕,就分析第i种物品可否加入进背包?
加几件(1件,2件,……,还是c[i]件?)是最好的,能产生最大价值。
注意:此题输入数据若较大的话,会产生较大的时间和空间。
实现过程若是如上所述的三维数组用四重循环填充,而后台测试数据有大至20 1000 500的数据,
2~3秒是必须的了,甚至更长。
若想运行时间尽可能小,应对四重循环的最内层精简,少几次比较操作或写数组操作都是有效的。
另外,还可以将每种物品的多件看作捆绑的多件物品(1件,捆绑2件,…,捆绑c[i]件),
在填充之前先一次性扩展n种物品的体积数组,重量数组,价值数组,把扩展后的背包问题视为每种物品一件。
再用三重循环进行填充,大家可以试一试看运行时间如何?
// 11083 旅游背包.cpp : 定义控制台应用程序的入口点。
//
#include <iostream>
#include <math.h>
using namespace std;
int dp[500][1001][501]={0};
int main()
{
int n,V,W;
cin>>n>>V>>W;
int vi,wi,ci,ti;
int v[500]={0}; //体积 10个物体1就有10个v,10个w,10个Val
int w[500]={0}; //重量
int Val[500]={0};//价值
int t1=0;//v、w、Val的指针t1
for(int i=1;i<=n;i++){
cin>>vi>>wi>>ci>>ti;
for(int i=1;i<=ci;i++){
t1++;
v[t1]=vi;
w[t1]=wi;
Val[t1]=ti;
}
}
for(int i=1;i<=t1;i++){
for(int j=1;j<=V;j++){
for(int k=1;k<=W;k++){
if(j-v[i]>=0 && k-w[i]>=0){
dp[i][j][k] = max(dp[i-1][j-v[i]][k-w[i]]+Val[i],dp[i-1][j][k]);
}
else dp[i][j][k] = dp[i-1][j][k];
}
}
}
cout<<dp[t1][V][W]<<endl;
return 0;
}