算法设计与分析 3.3 眯眯眼天使

★题目描述

共有N种商品参与促销。每种物品有价格Ci和原价Vi,以及限购数量Ki。

店主会在活动当天宣布有一种商品退出促销,无法购买。

为了获取最大利益,你准备提前计算好Q种情况。

即在给定携带资金Xi,和无法购买第Yi种物品的情况下,最多能够买走原价总和是多少。

特别提醒,商品论件出售,不允许拆分。

★输入格式

第一行包括一个正整数N,表示共有N件商品。

接下来的N行,每行包括三个自然数Ci, Vi, Ki。表示第i件商品的价格、原价和限购数量。

接下来的一行为Q,表示有Q种可能情况。

接下来的Q行,每行包括两个自然数Xi, Yi。 表示携带Xi块钱,无法购买第Yi种商品

★输出格式

输出包括Q行,每行包括一个正整数,表示对应的情况下你能买走的最大原价总和。

★样例输入

3
1 3 1
1 4 1
1 5 1
1
1 2

★样例输出

4

★提示

注意,商品编号从0开始。
对于60%的数据,N=50,Q=20。
对于100%的数据,1<=N<=800,1<=Q<=50000,1<=Ci,Vi,Ki<=100,0<=Yi<N,0<=Xi<=1000。

★参考代码

思路参考自共享文件

/*
该题是一道多重背包问题
因为本题有禁止购买商品
所以设立两个数组
f(i, j) 表示考虑前 i 种商品,花费 j 元能买的最大原件总和。
g(i, j) 表示考虑后 i 种商品,花费 j 元能买的最大原件总和。
对于单次询问 x, y,则把x元拆成两个部分(x1、x2)
前x1元用于买前y-1商品,后x2元用于买后y+1件商品 
*/ 
#include<bits/stdc++.h>
using namespace std;

const int M = 1000; //身上带的最多的钱
int C[800],V[800],K[800];
int F[801][3001], G[801][3001];

int main(){
	int N;
	scanf("%d",&N);
	for(int i=1; i<=N; ++i) scanf("%d%d%d",&C[i], &V[i], &K[i]);
	
	//正序购买商品 
	memset(F, 0, sizeof(F));
	for(int i=1; i<=N; ++i){ //考虑第i个商品 
		for(int k=0; k<=K[i]; ++k){   //第i个商品考虑买k个 
			for(int c=k*C[i]; c<=M; ++c){  //买该商品花费的钱 
				F[i][c] = max(F[i][c], F[i-1][c-k*C[i]]+k*V[i]); //产生的最大收益 
			}
		}
		for(int c=1; c<=M; ++c) F[i][c] = max(F[i][c], F[i][c-1]); //更新
	}
	
	//反序购买商品 
	memset(G, 0, sizeof(G));
	for(int i=N; i>0; --i){ //考虑第i个商品 
		for(int k=0; k<=K[i]; ++k){   //第i个商品考虑买k个 
			for(int c=k*C[i]; c<=M; ++c){  //买该商品花费的钱 
				G[i][c] = max(G[i][c], G[i+1][c-k*C[i]]+k*V[i]); //产生的最大收益 
			}
		}
		for(int c=1; c<=M; ++c) G[i][c] = max(G[i][c], G[i][c-1]); //更新 
	}

	int Q,x,y;
	scanf("%d",&Q);
	while(Q--){
		scanf("%d%d",&x, &y); 
		++y;  //因为商品编号从0开始 
		
		int ans=0;
		for(int c=0; c<=x; ++c){
			ans = max(ans, F[y-1][c]+G[y+1][x-c]); //第y个商品禁买,花费c买前y-1个商品,花费x-c买后y+1个商品 
		}	
		printf("%d\n",ans);
	}
	return 0;
}

posted on 2019-12-18 16:24  yejifeng  阅读(1791)  评论(0编辑  收藏  举报

导航