动态规划 - 以最大利润销售的葡萄酒

时间:2017-06-13 07:16:17

标签: recursion data-structures dynamic-programming memoization

让我们考虑一下您在架子上放置的N种葡萄酒的集合。第i种葡萄酒的价格是pi。 (不同葡萄酒的价格可能不同)。因为葡萄酒每年变得更好,假设今天是第1年,第y年葡萄酒的价格将是y * pi,即当前年份的y倍。 你想卖掉你所有的葡萄酒,但是你想要从今年开始每年出售一种葡萄酒。还有一个限制因素 - 每年你只允许卖掉货架上最左边或最右边的葡萄酒,你不能重新订购货架上的葡萄酒(即它们必须保持与开始时相同的顺序) )。 您想了解一下,如果以最佳顺序销售葡萄酒,您可以获得的最大利润是多少?

int N; // number of wines 
int p[N]; // array of wine prices
int cache[N][N]; // all values initialized to -1 
    int profit(int be, int en) {
        if (be > en)
            return 0;
        if (cache[be][en] != -1)
            return cache[be][en];
    int year = N - (en-be+1) + 1;
    return cache[be][en] = max(profit(be+1, en) + year * p[be],profit(be, en-1) + year * p[en]);
    }

时间复杂度:O(n ^ 2)。 我已经找到了这个O(n ^ 2)解决方案。我们可以在O(n)中做到吗? (更好的时间复杂性)

1 个答案:

答案 0 :(得分:1)

你应该通过出售货架上的所有葡萄酒来找到最优的成本。唯一的限制是你可以只挑选左边或右边的酒(你不能从货架中间挑选一个酒瓶)。
当我们被允许选择左或右葡萄酒时,最佳解决方案序列将包括左或右瓶
让我们为此找到一个递归解决方案。

  1. 只需拿起左瓶并计算成本
  2. 拿起合适的瓶子并计算成本
  3. 比较成本并选择最高成本
  4. 为基本案例写下必要条件
  5. 让我们为此编写一个c ++程序 -

    #include<bits/stdc++.h>
    using namespace std;
    int max_cost(int wine[], int cost, int counter, int i, int j){
    
    
        // Here `counter` keeps track of the number of years
        // `i` is the left indices of the shelf
        // `j` is the right indices of the shelf
        // `cost` is the maximum cost that we have to find
    
    
        if(i > j)
            return cost;
        else if(i == j){
            cost += counter * wine[i];
            return cost;
        }
        else{
            int cost1 = counter * wine[i] + max_cost(wine, 0, counter + 1, i + 1, j);
            int cost2 = counter * wine[j] + max_cost(wine, 0, counter + 1, i, j - 1);
            cost += max(cost1, cost2);
            return cost;
        }
    }
    int main(){
        int n;
        cin >> n;
        int wine[n];
        for(int j = 0; j < n; ++j)
            cin >> wine[j];
        cout << max_cost(wine, 0, 1, 0, n - 1) << endl;
        return 0;
    }
    

    我认为上面的代码是自我解释的 让我们来运行它:

    Input1:
    5
    1
    3
    1
    5
    2
    Output:
    43
    
    Input2:
    4
    10
    1
    10
    9
    Output:
    79
    

    上述代码的时间复杂度为O(2 ^ n),其中n为否。在架子上的酒瓶。
    我们可以即兴表达时间复杂度吗? 当然。我们基本上是一次又一次地计算一些序列,这可以通过记忆技术来避免 递归关系基本相同。除此之外,我们还会记住特定ij的值。因此,我们不必一次又一次地计算同一ij的值 c ++代码将是 -

    #include<bits/stdc++.h>
    using namespace std;
    int find_cost(vector<int>& box, vector<vector<int>>& dp, int i, int j){
        if(i == j)        // base case
            dp[i][j] = box[i] * box.size();
        else if(!dp[i][j]){        // If not calculated so far
            int n = box.size();
            dp[i][j] = max(find_cost(box, dp, i, j - 1) + box[j] * (n - (j - i)), 
                            find_cost(box, dp, i + 1, j) + box[i] * (n - (j - i)));
        }
        return dp[i][j];
    }
    void cost_wine(vector<int> box){
        int n = box.size();
        vector<vector<int>> dp(n + 1, vector<int>(n + 1));  // Initialize dp array
        cout << find_cost(box, dp, 0, n - 1);
        return;
    }
    int main(){
        int n;
        cin >> n;
        vector<int> box(n);
        for(int i = 0; i < n; ++i)
            cin >> box[i];
        cost_wine(box);
        return 0;
    }
    

    现在上面代码的时间复杂度为O(n ^ 2),远远好于递归方法。