點菜問題(經典0-1揹包)
阿新 • • 發佈:2022-03-05
動態規劃——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 -------------------------------------------------*/ #include <bits/stdc++.h> using 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 ------------------------------------------------- */ #include <bits/stdc++.h> using 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] = price[j]; } else { price[j] = max(price[j-weight[i]]+value[i],price[j]); //判斷到底是犧牲空間給i物品的總價值高還是保持沒有i物品時揹包容量是j的價值高 } } } cout << price[m] << endl; } return 0; }