股票买卖

题目来源:http://bailian.openjudge.cn/practice/4121/

解题思路

  • 假设股票数组为prices
  • 设F[k][i]表示到第i天总共买卖k次时的最大利润,可以将其分为两种情况,即第i天卖出股票和未卖出股票。
  • 假如第i天没有卖出股票,F[k][i] = F[k][i-1]
  • 假如第i天卖出了股票,那么F[k][i] = max{prices[i] - prices[t]+F[k-1][t]},为什么是这个推导公式,因为假如F[k][i]的最优解是,第x天是k-1次的卖出,随后的第y天又买入,第i天卖出,于是F[k][i] = F[k-1][x]+prices[i]- prices[y](x<= y <=i),此时必然有F[k-1][x] =F[k-1][y],证明如下:
    • 很显然,F[k-1][y]>=F[k-1][x],假设F[k-1][y]>F[k-1][x],此时必然有F[k-1][y]+prices[i]-prices[y]>F[k][i] = F[k-1][x]+prices[i]- prices[y],这与最优解矛盾,因此必然有F[k-1][x] =F[k-1][y],因此F[k][i]的推导公式可以写成max{prices[i] - prices[t]+F[k-1][t]}。
  • 对上述进行优化,max{prices[i] - prices[t]+F[k-1][t]} = prices[i] +max{F[k-1][t]-prices[t]}; (0<=t<=i-1), 对于确定的i和k,每次求max{F[k-1][t]-prices[t]}都需要对t从1到i进行遍历,于是可以在循环中,求解时用一个临时变量tmp记录max{F[k-1][t]-prices[t]},t属于[0,i-1],每次i增量时比较tmp和F[k-1][i]-prices[i]和tmp的较大值赋给tmp,再进行求解。

AC代码

代码中nums即为解题思路中的prices

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <vector>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <climits>
#include <string>
#include <algorithm>

using namespace std;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef const int CI;

int solution(const VI& nums, CI K) {
VVI F(K + 1, VI(nums.size(), 0));
for (int k = 1; k <= K; ++k) {
int tmp = F[k - 1][0] - nums[0];
for (int i = 1; i < nums.size(); ++i) {
tmp = max(F[k-1][i] - nums[i], tmp);
F[k][i] = max(F[k][i - 1], nums[i] + tmp);
}
}
return F[K][nums.size() - 1];
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int castCount; cin >> castCount;
while (castCount--) {
int N;
cin >> N;
VI nums(N, 0);
for (auto&e : nums)
cin >> e;
int ans = solution(nums,2);
cout << ans << endl;
}
return 0;
}