1. 程式人生 > 其它 >點菜問題(經典0-1揹包)

點菜問題(經典0-1揹包)

動態規劃——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;
}