11083 旅游背包(优先做)

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值