点菜问题(北京大学复试上机题)(0-1背包问题)
本文目录
题目描述:
北大网络实验室经常有活动需要叫外卖,但是每次叫外卖的报销经费的总额最大为C元,有N种菜可以点,经过长时间的点菜,网络实验室对于每种菜 i 都有一个量化的评价分数(表示这个菜可口程度),为Vi,每种菜的价格为Pi, 问如何选择各种菜,使得在报销额度范围内能使点到的菜的总评价分数最大。
注意:由于需要营养多样化,每种菜只能点一次。
输入格式:
输入的第一行有两个整数C和N,C代表总共能够报销的额度,N代表能点菜的数目。
接下来的N行每行包括两个整数Pi和Vi,分别表示第 i 道菜的价格和评价分数。
输出格式:
输出共一行,一个整数,表示在报销额度范围内,所点的菜能够得到的最大评价分数。
数据范围:
1≤C≤1000,
1≤N≤100,
1≤Pi,Vi≤100
输入样例: | 输出样例: |
---|---|
90 4 20 25 30 20 40 50 10 18 |
95 |
题解(以本题内容作答,和0-1背包问题思路完全一致)
一、二维解法
解题思路:
- 状态定义:
dp(i,j)
表示前 i 道菜品,在报销额度为 j 的情况下的最大总评价分数。 - 分支情况(状态转移方程):对于前 i 道菜品的总评价分数
dp(i,j)
:- 不选择第 i 道菜品,那么
dp(i,j) = dp(i - 1, j)
,即和前i - 1道菜的总评价分数一致; - 选择第 i 道菜品,那么
dp(i,j) = dp(i - 1, j - Pi) + Vi
,即为前 i - 1道菜品在报销额度为j - Pi
的最大总评价分数与第 i 道菜品的评价分数之和。
- 不选择第 i 道菜品,那么
- 那么什么时候加入第 i 道菜,什么时候不加入第 i 道菜呢?(第 i 道菜的价格记录在price[i - 1],评价分数记录在score[i - 1],报销额度是 j)
- 第一种情况是,当我们第 i 道菜的价格大于报销额度 j 时(即
price[i - 1] > j
),显而易见,不能加入。 - 第二种情况是,第 i 道菜的价格小于报销额度(即
price[i - 1] < j
)时,若加入第 i 道菜后,前 i 道菜的总评价分数大于不加入第 i 道菜时前 i 道菜的总评价分数, 即dp[i - 1, j] < dp[i - 1, j - price[i - 1]] + score[i - 1]
时,选择加入。
- 第一种情况是,当我们第 i 道菜的价格大于报销额度 j 时(即
- 综上所述,便有核心代码:
if (price[i - 1] > j)
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - price[i - 1]] + score[i - 1]);
AC代码:
#include <iostream>