【问题标题】:Dynamic Programming - The wine selling with maximum profit动态规划 - 以最大利润销售葡萄酒
【发布时间】:2017-11-14 19:55:52
【问题描述】:

假设您有 N 种葡萄酒并排放置在一个架子上。第 i 种酒的价格是 pi。 (不同酒的价格可能不同)。因为葡萄酒每年都在变好,假设今天是第 1 年,那么在第 y 年,第 i 种葡萄酒的价格将为 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) 中做到吗? (更好的时间复杂度)

【问题讨论】:

  • 您能否为上述问题提供一个示例输入和输出?对我来说测试我的代码会更容易,谢谢
  • 我假设上述问题的一个例子可能是输入:- 10, 1, 2, 6, 7。所以我挑选要出售的葡萄酒的顺序将是这样的 - 7,6,2,1,10 所以我的总利润将是 = 7*1 + 6*2 + 2*3 + 1*4 + 10*5 = 159。如果我错了请告诉我?
  • @zenwraight 是的。考虑这个例子: p[] = {2, 3, 5, 1, 4} 并且解决方案将是 2 * 1 + 4 * 2 + 1 * 3 + 3 * 4 + 5 * 5 = 50
  • 根据我的说法,使用 O(n) 是不可能的,因为那样它不会涵盖所有可能性,dp 和 O(n^2) 似乎只是解决问题的正确方法这个

标签: recursion data-structures dynamic-programming memoization


【解决方案1】:

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

  1. 拿起左边的瓶子,计算一下它的成本
  2. 拿起正确的瓶子并计算成本
  3. 比较成本并选择最大成本
  4. 写出基本情况的必要条件

让我们为此编写一个 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),比递归的方法要好很多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-28
    • 2017-05-01
    • 2011-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多