股票买卖 题解

题目来源: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[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

#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;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值