点菜问题(0-1背包)
题目
描述
北大网络实验室经常有活动需要叫外卖,但是每次叫外卖的报销经费的总额最大为C元,有N种菜可以点,经过长时间的点菜,网络实验室对于每种菜i都有一个量化的评价分数(表示这个菜可口程度),为Vi,每种菜的价格为Pi, 问如何选择各种菜,使得在报销额度范围内能使点到的菜的总评价分数最大。 注意:由于需要营养多样化,每种菜只能点一次。输入描述:
输入的第一行有两个整数C(1 <= C <= 1000)和N(1 <= N <= 100),C代表总共能够报销的额度,N>代表能点菜的数目。接下来的N行每行包括两个在1到100之间(包括1和100)的的整数,分别表示菜的>价格和菜的评价分数。输出描述:
输出只包括一行,这一行只包含一个整数,表示在报销额度范围内,所点的菜得到的最大评价分数。输入:
90 4 20 25 30 20 40 50 10 18 40 2 25 30 10 8输出:
95 38
分析
0-1背包问题自己想听抽象的,但其实相对前面的最长递增子序列而言真的挺简单的
(回头想录个视频来好好分析一下~别急)
解答(时间O(n*m),空间O(n*m))
(飘过~击败牛客网3%hhhhhhh~)
/* ------------------------------------------------- Author: wry date: 2022/3/5 14:54 Description: 0-1bag ------------------------------------------------- */ #includeusing namespace std; const int MAXN = 1000+10; int price[MAXN][MAXN]; //总价值 int weight[MAXN]; int value[MAXN]; int main() { int n,m; //n表示物品数目、m表示背包最大容量 while (cin >> m >> n) { memset(price,0, sizeof(price)); for (int i=1;i<=n;i++) { cin >> weight[i] >> value[i]; } for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) { if (j<weight[i]) { price[i][j] = price[i-1][j]; } else { price[i][j] = max(price[i-1][j-weight[i]]+value[i],price[i-1][j]); //判断到底是牺牲空间给i物品的总价值高还是保持没有i物品时背包容量是j的价值高 } } } cout << price[n][m] << endl; } return 0; }
优化代码(时间O(n*m),空间O(m))
(优化十分巧妙,因为在上面的代码中,每一行的price的值都只取决于上一行的值(max(price[i-1][j-weight[i]]+value[i],price[i-1][j]))可以很清晰看见i行都是取决于i-1行,因此优化的方案就是不再使用二维数组,只用一维数组,每次更新从后往前更新,这样就不会出现覆盖错误!我只能说——妙啊~(超过80%hhhhhh~))
/* ------------------------------------------------- Author: wry date: 2022/3/5 14:54 Description: 0-1bag ------------------------------------------------- */ #includeusing namespace std; const int MAXN = 1000+10; int price[MAXN]; //总价值(从后向前更新) int weight[MAXN]; int value[MAXN]; int main() { int n,m; //n表示物品数目、m表示背包最大容量 while (cin >> m >> n) { memset(price,0, sizeof(price)); for (int i=1;i<=n;i++) { cin >> weight[i] >> value[i]; } for (int i=1;i<=n;i++) { for (int j=m;j>=1;j--) { //每次从后往前更新 if (j>=weight[i]){ price[j] = max(price[j-weight[i]]+value[i],price[j]); //判断到底是牺牲空间给i物品的总价值高还是保持没有i物品时背包容量是j的价值高 } // else{ // price[j] = price[j]; // } } } cout << price[m] << endl; } return 0; }