可以获得的最大利润 - 购买和销售

时间:2017-01-03 20:06:25

标签: algorithm dynamic-programming

假设我们准确预测梅西的价格为N天。预测以列表形式给出,其中p_i表示玩家在日i的价格。鲍勃计划在此期间进行多次连续交易,但一次不能有多个梅西,因此在再次购买之前需要卖掉他。

鲍勃以有限的预算B开始,不能买一个费用超出他能力的梅西。当然,鲍勃可以通​​过购买和出售他的Messis获得任何利润。对他来说幸运的是,有些时候他开始与梅西一起打开一个随意的礼品包。

最后鲍勃只想获得尽可能多的利润,然后卖掉最后一次梅西。

输入格式:

在输入文件的第一行,您将找到3个整数,N,B和M.

N表示Bob预测梅西价格的天数。 B代表Bob的初始预算。 M可以是0或1;如果Bob在没有初始Messi的情况下开始卖出,则为0;如果他确实以最初的Messi开始卖出,则为1。

在下一行,你会发现N个整数:p1,p2,...,pN,用空格分隔,其中pi代表梅西在第i天的价格。

给出测试用例

测试1

7 5 0

20 10 30 5 10 10 20

正确答案:15

说明:Bob的初始预算为5,没有初始的Messi可供出售。他的价格下降到5之前他不能买任何梅西,所以他的利润只有(20-5)= 15

测试2

7 0 1

20 10 50 80 60 20 10

正确答案:90

说明: 鲍勃的初始预算为0,一个梅西出售。因此他卖掉了他最初的梅西20分,买回他10分,卖给他80分,所以他的利润是20 +(80-10)= 90

这个问题是在一次采访中给我的,但是我无法提供一个有效的解决方案。与此同时,我发现了一些关于这个问题的更简单的变体,例如Maximum profit by buying and selling a share at most twice,但我一直没有成功地理解如何使思维适应我的问题。

到目前为止,我只能提出一种超出我给出的时间限制的强力解决方案(C ++为0.1秒,其中1 <= N <= 10 ^ 5)。

我正在寻找一种解决方案和一种思考这类问题的方法,我似乎无法找到正确的思考方式。

3 个答案:

答案 0 :(得分:2)

我们可以使用动态编程。

  1. 如果我们在一天开始时没有Messi f0(i),我们可以将i定义为我们可以获得的最高预算。 如果我们得到他,请f1(i)为相同的值。

  2. i = 0的基本值取决于我们是否在一开始就拥有他。

  3. 转换如下:

    • 我们可以从i转到i + 1并且什么都不做

    • 如果我们有梅西,我们可以卖他(设置f0(i + 1) = max(f0(i + 1), f1(i) + price(i))

    • 如果我们没有他,我们的预算足够大,我们可以买他 (做f1(i + 1) = max(f1(i + 1), f0(i) - price(i))

  4. 答案是f0(n)(这意味着所有日子过去了,我们没有他)。

  5. 这个解决方案显然需要线性的时间和空间,所以任何 合理的C ++实现应该符合您的要求。

答案 1 :(得分:1)

问题的第一个简化是转换最初的礼物&#34;在梅西的初始价格下,梅西获得相同数额的金钱。用户可以选择在开始时回购梅西。

之后,您会发现第一个价格足以让用户购买梅西,并在此之前丢弃每个预测。然后,查找预测价格的所有本地最小和本地最大值,并购买所有最小值并卖出所有最大值,但请记住不要回购,如果局部极小是最后的预测。

这应解决O(N)中的问题。

编辑:可以通过序列的二度差异找到局部最小值或最大值:

d[i] = p[i+1] - p[i]
d2[i] = d[i] - d[i-1]

如果d2[i] > 0,则它是本地最小的;如果d2[i] < 0,那么它是本地最大值。显然,你需要注意一些边界条件,但它不应该太难。

答案 2 :(得分:0)

// input
long predictionLength;
long budget;
bool startWithMessi;
long prediction[MAX_PREDICTION_LENGTH];

// output
long profit;

ifstream fin;
fin.open( DATA_FILE_NAME );
fin >> predictionLength >> budget >> startWithMessi;
for( long day = 0; day < predictionLength; day++ )
  fin >> prediction[day];
fin.close();

long money = budget;
bool messi = startWithMessi;
long dayIndex = 0;
while( dayIndex < predictionLength )
{
  if( messi )
  {
    if( dayIndex == predictionLength - 1
      || prediction[dayIndex] > prediction[dayIndex + 1] )
    {
      money += prediction[dayIndex];
      messi = false;
    }
  }
  else
    if( dayIndex < predictionLength - 1
      && prediction[dayIndex] < prediction[dayIndex + 1]
      && money >= prediction[dayIndex] )
    {
      money -= prediction[dayIndex];
      messi = true;
    }
  dayIndex++;
}

profit = money - budget;

cout << profit << endl;