【题目来源】
https://www.acwing.com/problem/content/1057/
【题目描述】
给定一个长度为 N 的数组,数组中的第 i 个数字表示一个给定股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
【输入格式】
第一行包含整数 N,表示数组长度。
第二行包含 N 个不大于 10000 的正整数,表示完整的数组。
【输出格式】
输出一个整数,表示最大利润。
【输入样例1】
6
7 1 5 3 6 4
【输出样例1】
7
【输入样例2】
5
1 2 3 4 5
【输出样例2】
4
【输入样例3】
5
7 6 4 3 1
【输出样例3】
0
【样例解释】
样例1:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。共得利润 4+3 = 7。
样例2:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
样例3:在这种情况下, 不进行任何交易, 所以最大利润为 0。
【数据范围】
1≤N≤10^5
【算法分析】
● 状态定义
dp[i][0]:第 i 天结束时,不持有股票的最大收益
dp[i][1]:第 i 天结束时,持有股票的最大收益
● 转移分析(最后一步分析法)
1. dp[i][0]:第 i 天不持有股票。两种来源:
- 前一天本来就不持有,今天什么都不做:dp[i-1][0]
- 前一天持有股票,今天卖出:dp[i-1][1] + a[i]
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+a[i])
2. dp[i][1]:第 i 天持有股票。两种来源:
- 前一天已经持有,今天不动:dp[i-1][1]
- 前一天无股票,今天买入:dp[i-1][0]-a[i]
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-a[i])
● 边界:
dp[0][0]=0:第 0 天,无股票,收益 0
dp[0][1]=-inf:第 0 天不可能持有股票,负无穷(非法状态)
● 最终答案:dp[n][0],最后一天一定不持有股票(卖出才兑现利润)
【算法代码】
#include <bits/stdc++.h> using namespace std; const int inf=0x3f3f3f3f; const int N=1e5+5; int dp[N][2]; int a[N]; int main() { int n; cin>>n; for(int i=1; i<=n; i++) { cin>>a[i]; } dp[0][0]=0, dp[0][1]=-inf; for(int i=1; i<=n; i++) { dp[i][0]=max(dp[i-1][0],dp[i-1][1]+a[i]); dp[i][1]=max(dp[i-1][1],dp[i-1][0]-a[i]); } cout<<dp[n][0]<<endl; return 0; } /* in: 6 7 1 5 3 6 4 out: 7 */
【参考文献】
https://www.acwing.com/solution/content/38975/