美团校招-2023.3.18.10点-第四题-商店-困难

商店

Problem Description

在商店里有N个物品,每个物品有原价和折扣价小美相要购买商品。小美拥有X元,一共Y张折扣券。小美需要最大化购买商品的数量,并在所购商品数量尽量多的前提下,尽量减少花费。 你的任务是帮助小美求出最优情况下的商品购买数量和花费的钱数。

input

第一行三个整数,以空格分开,分别表示N,X,Y。接下来N行,每行两个整数,以空格分开,表示一个的原价和折扣价。1≤N≤100,1≤X≤5000,1≤Y≤50,每个商品原价和折扣价均介于[1,50]之间。

ouput

一行,两个整数,以空格分开。第一个数字表示最多买几个商品,第二个数字表示在满足商品尽量多的前提下所花费的最少的钱数。

Sample Input 1

3 5 1
4 3
3 1
6 5

Sample Output 1

2 5

Sample Input 2

3 5 1
4 3
3 1
6 1

Sample Output 2

2 4

Sample Input 3

10 30 3
2 1
3 2
2 1
10 8
6 5
4 3
2 1
10 9
5 4
4 2

Sample Output 3

8 24

题目类型、难度、来源

总体思路:

  • 此题的难点在于有不确定数量的折扣卷。如果折扣卷无限或没有折扣卷,那么这题就可以使用贪心来做。
  • 此题应该用动态规划,使用** d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示前i个商品,花费了j元,用掉了k张折扣卷能买到的商品数量**。使用price[i]表示第i个商品的价格,lowprice[i]表示第i个商品的折扣价。
    • i从1开始,前i=0个表示个表示没有商品,因此边界条件就确定了,即 d p [ 0 ] [ 0 ] [ 0 ] = 0 dp[0][0][0]=0 dp[0][0][0]=0。使用-1表示状态该状态非法。
    • 状态转移:在考虑第i个商品时,只有三种情况:
      • 不买第i个商品。此时很显然用掉的钱及用掉的折扣卷数量和前i-1个商品的情况一样,即 d p [ i ] [ j ] [ k ] = d [ i − 1 ] [ j ] [ k ] dp[i][j][k] = d[i-1][j][k] dp[i][j][k]=d[i1][j][k]
      • 原价购买第i个商品。此时有 d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j − p r i c e [ i ] ] [ k ] + 1 dp[i][j][k] = dp[i-1][j-price[i]][k]+1 dp[i][j][k]=dp[i1][jprice[i]][k]+1
      • 在有折扣卷的情况下,使用折扣卷购买第i个商品。此时有 d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j − l o w p r i c e [ i ] ] [ k − 1 ] + 1 dp[i][j][k] = dp[i-1][j-lowprice[i]][k-1]+1 dp[i][j][k]=dp[i1][jlowprice[i]][k1]+1
    • 因为题目要求最多买多少商品,因此状态转移方程为: d p [ i ] [ j ] [ k ] = m a x ( d [ i − 1 ] [ j ] [ k ] , d p [ i − 1 ] [ j − p r i c e [ i ] ] [ k ] + 1 , d p [ i − 1 ] [ j − l o w p r i c e [ i ] ] [ k − 1 ] + 1 ) dp[i][j][k]=max(d[i-1][j][k], dp[i-1][j-price[i]][k]+1, dp[i-1][j-lowprice[i]][k-1]+1) dp[i][j][k]=max(d[i1][j][k],dp[i1][jprice[i]][k]+1,dp[i1][jlowprice[i]][k1]+1)
  • 因为状态转移方程过于复杂,很难找到一个更新dp数组的顺序。因此需要反过来思考。即使用 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]去更新 d [ i + 1 ] [ j ] [ k ] d[i+1][j][k] d[i+1][j][k] d p [ i + 1 ] [ j + p r i c e [ i + 1 ] ] [ k ] dp[i+1][j+price[i+1]][k] dp[i+1][j+price[i+1]][k] d p [ i + 1 ] [ j + l o w p r i c e [ i + 1 ] ] [ k + 1 ] dp[i+1][j+lowprice[i+1]][k+1] dp[i+1][j+lowprice[i+1]][k+1]

AC代码

#include <iostream>
#include <algorithm>
using namespace std;
int main(){
    
    
	int N, X, Y;
	cin >> N >> X >> Y;
	// 原价 
	int *price = new int[N+5];
	//折扣价 
	int *low_price = new int[N+5];
	for (int i = 0; i < N; i++){
    
    
		cin >> price[i] >> low_price[i];
	}
	// 初始化dp数组 
	int dp[N+5][X+10][Y+10] = {
    
    0};
	for (int i = 0; i <= N; i++){
    
    
		for (int j = 0; j <= X; j++){
    
    
			for (int k = 0; k <= Y; k++){
    
    
				dp[i][j][k] = -1;
			}
		}
	}
	// 前i=0个商品表示没有商品,因此dp[0][0][0]只能为0 
	dp[0][0][0] = 0;
	
	for (int i = 0; i < N; i++){
    
    
		for (int j = 0; j <= X; j++){
    
    
			for (int k = 0; k <= Y; k++){
    
    
				if (dp[i][j][k] == -1)	continue;
				dp[i+1][j][k] = max(dp[i][j][k], dp[i+1][j][k]);
				if (j+price[i] <= X){
    
    
					dp[i+1][j+price[i]][k] = max(dp[i][j][k]+1, dp[i+1][j+price[i]][k]);
				}
				if (j+low_price[i] <= X && k+1 <= Y){
    
    
					dp[i+1][j+low_price[i]][k+1] = max(dp[i][j][k]+1, dp[i+1][j+low_price[i]][k+1]);
				}
			}
		}
	}
	
	int max_sum = -1, min_cost = 1000000000;
	for (int i = 1; i <= N; i++){
    
    
		for (int j = 0; j <= X; j++){
    
    
			for (int k = 0; k <= Y; k++){
    
    	
				if (dp[i][j][k] > max_sum){
    
    
					max_sum = dp[i][j][k];
					min_cost = j;
				}else if (dp[i][j][k] == max_sum){
    
    
					if (j < min_cost){
    
    
						min_cost = j;
					}
				}
			}
		}
	}	
	cout << max_sum << " " << min_cost;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_40735291/article/details/129658211