动态规划-DP-——股票问题_股票问题dp_RUML的博客-程序员秘密

技术标签: 算法  c++  c语言  动态规划  数据结构  算法与数据结构  

股票问题(简单DP)

摘要


本文主要介绍了和DP相关的股票问题,分析比较简单,容易理解,适合刚接触DP的朋友们学习。

股票Ⅰ

题面


假设您有一个数组,第i个元素是第i天给定股票的价格。

如果只允许您最多完成一笔交易(即买入和卖出一股股票),请设计一种算法以找到最大的利润(卖出的价格-买入的价格)。

请注意,您不能在买股票之前卖出股票。

输入


多组输入数据

每组数据第一行一个数n,(1≤n≤105)

接下来一行n个数表示股票的价格(1≤ai≤109)

输出


每组数据一行一个数。

输入样例


5
1 2 3 4 5

输出样例


4

AC代码


#include<iostream>
#include<cstdio>
using namespace std;
int max(int n,int m){
    
	if(n>=m) return n;
	return m;
}
int main(){
    
	int n,a[100005]={
    };
	long long buy,sell;
	while(~scanf("%d",&n)){
    
		buy1=-1000000001,sell1=0;
		for(int i=1;i<=n;i++){
    
			scanf("%d",&a[i]);
		}
		for(int i=1;i<=n;i++){
    
			buy=max(buy,-a[i]);
			sell=max(sell,buy+a[i]);
		}
		printf("%lld\n",sell);
	}
}

分析


我们直接从DP的角度开始分析这个问题,首先看清题意,只能买入和卖出一股股票,并且卖出必须在买入之后完成。那么我们每一天的选择就是买或者不买或者卖,也就是有两种状态买buy和卖sell,而买入股票对应的就是花钱,我们最开始的钱为0,买入后就变会损失也就是-a[i],并且当天的总收益就为-a[i],也就是buy的值,卖出后则为收益也就是+a[i],并且当天的总收益就为buy+a[i]。所以我们就考虑当天买和之前买了(即与之前buy里的值进行比较)哪个收益更高,同时当天卖和之前已经卖了(即与之前sell里的值进行比较)哪个收益更高即可完成。

转移方程


  • buy = max(buy, -a[i])
  • sell = max(sell, buy+a[i])

HINT


首先观察数据范围发现最终结果是可能超int的,所以对buysell的定义应为long long,然后是buy的初始值应该设置为负值而不是0,因为第一次买入的时候此时总收益就为负值。



股票Ⅱ


题面


假设您有一个数组,第i个元素是第i天给定股票的价格。

设计算法以找到最大的利润。您可以根据需要完成尽可能多的交易。

请注意,无法同时进行多项交易(即必须先出售股票才能再次购买)

输入


多组输入数据

每组数据第一行一个数n,(1≤n≤105)

接下来一行n个数表示股票的价格(1≤ai≤109)

输出


每组数据一行一个数

输入样例


5
1 2 3 4 5

输出样例


4

AC代码


#include<iostream>
#include<cstdio>
using namespace std;
int max(int n,int m){
    
	if(n>=m) return n;
	return m;
}
int main(){
    
	int n,a[100005]={
    };
	long long buy,sell;
	while(~scanf("%d",&n)){
    
		buy=-1000000001,sell=0;
		for(int i=1;i<=n;i++){
    
			scanf("%d",&a[i]);
		}
		for(int i=1;i<=n;i++){
    
			buy=max(buy,sell-a[i]);
			sell=max(sell,buy+a[i]);
		}
		printf("%lld\n",sell);
	}
}

分析


我们直接从上一问的思路继续分析,本题是要求利润最大并且可以完成任意多的交易(即可以买了又卖卖了再买),那我们还是同样分析,买了之后当天的总收益为sell-a[i](因为之前是处于卖了之后的状态所以用sell来减),然后卖了之后当天的总收益为buy-a[i](因为之前是处于买了之后的状态所以用buy来减),然后我们考虑每一天的情况即可。

转移方程


  • buy = max(buy, sell-a[i])

  • sell = max(sell, buy+a[i])

HINT


还是一样需要注意数据类型的选择和buy的初始赋值,然后是sell最初值置0才能保证第一次买后总收益的正确性。



股票Ⅲ


题面


假设您有一个数组,第i个元素是第i天给定股票的价格。

设计算法以找到最大的利润。您最多可以完成两次交易。

请注意,无法同时进行多项交易(即必须先出售股票才能再次购买)

输入


多组输入数据

每组数据第一行一个数n,(1≤n≤105)

接下来一行n个数表示股票的价格(1≤ai≤109)

输出


每组数据一行一个数

输入样例


5
1 2 3 4 5

输出样例


4

AC代码


#include<iostream>
#include<cstdio>
using namespace std;
int max(int n,int m){
    
	if(n>=m) return n;
	return m;
}
int main(){
    
	int n,a[100005]={
    };
	long long buy1,sell1,buy2,sell2;
	while(~scanf("%d",&n)){
    
		buy1=-1000000001,sell1=0,buy2=-1000000001,sell2=0;
		for(int i=1;i<=n;i++){
    
			scanf("%d",&a[i]);
		}
		for(int i=1;i<=n;i++){
    
			buy1=max(buy1,-a[i]);
			sell1=max(sell1,buy1+a[i]);	
			buy2=max(buy2,sell1-a[i]);
			sell2=max(sell2,buy2+a[i]);
		}
		printf("%lld\n",sell2);
	}
}

分析


我们还是延续思路继续分析,本题是要求利润最大并且只能完成两次交易,那我们还是同样分析,因为有两次交易,所以需要4个变量来存,第一次买了之后当天的总收益为-a[i](因为相当于之前没有卖出),然后第一次卖了之后当天的总收益为buy1-a[i](因为之前是处于第一次买了之后的状态所以用buy1来减),然后第二次买了之后当天的总收益为sell1-a[i](因为相当于之前有一次卖出),然后第二次卖了之后当天的总收益为buy2-a[i](因为之前是处于第二次买了之后的状态所以用buy2来减),然后我们考虑每一天的情况即可。

转移方程


  • buy1=max(buy1,-a[i]);
  • sell1=max(sell1,buy1+a[i]);
  • buy2=max(buy2,sell1-a[i]);
  • sell2=max(sell2,buy2+a[i]);

HINT


还是一样需要注意数据类型的选择和sell1、buy1、buy2的初始赋值,然后是sell1最初值置0才能保证第一次买后总收益的正确性。然后是对方程的理解,是怎么样实现的。



股票Ⅳ


题面


假设您有一个数组,第i个元素是第i天给定股票的价格。

设计算法以找到最大的利润。您最多可以完成k次交易。

请注意,无法同时进行多项交易(即必须先出售股票才能再次购买)

输入


多组输入数据

每组数据第一行两个数n,k,(1≤n,k≤103)

接下来一行n个数表示股票的价格(1≤ai≤109)

输出


每组数据一行一个数

输入样例


5 2
1 2 3 4 5

输出样例


4

AC代码


#include<iostream>
#include<cstdio>
using namespace std;
int max(int n,int m){
    
	if(n>=m) return n;
	return m;
}
int main(){
    
	int n,k,a[100005]={
    };
	long long buy[1005],sell[1005];
	while(~scanf("%d%d",&n,&k)){
    
		for(int i=1;i<=n;i++){
    
			scanf("%d",&a[i]);
		}
		for(int i=1;i<=k;i++){
    
			buy[i]=-1000000001;
			sell[i]=0;
		}
		for(int i=1;i<=n;i++){
    
			buy[1]=max(buy[1],-a[i]);
			sell[1]=max(sell[1],buy[1]+a[i]);
			for(int j=2;j<=k;j++){
    
				buy[j]=max(buy[j],sell[j-1]-a[i]);
				sell[j]=max(sell[j],buy[j]+a[i]);
			}
		}
		printf("%lld\n",sell[k]);
	}
}

分析


我们还是相同思路继续分析,本题是要求利润最大并且只能完成k次交易,因为有k次交易,所以需要2k个变量来存,即用两个数组来存即可,第一次买了之后当天的总收益为-a[i](因为相当于之前没有卖出),然后第一次卖了之后当天的总收益为buy[1]-a[i](因为之前是处于第一次买了之后的状态所以用buy[1]来减),然后第二次买了之后当天的总收益为sell[1]-a[i](因为相当于之前有一次卖出),然后第二次卖了之后当天的总收益为buy[2]-a[i](因为之前是处于第二次买了之后的状态所以用buy[2]]来减),然后用一个从2-k的循环来实现此过程即可。

转移方程


  • buy[j]=max(buy[j], sell[j-1]-a[i])
  • sell[j]=max(sell[j], buy[j]+a[i])

HINT


还是一样需要注意数据类型的选择和buy[],sell[]的初始赋值,然后是上文的AC代码的循环其实不用把buy[1]、sell[1]单独拿出来讨论的,只是更方便理解。

题目来源


北航OJ



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_43780964/article/details/106031437

智能推荐

mysql有索引但不走索引的典型场景_weixin_39723233的博客-程序员秘密

1、数据类型发生隐式转换如下sql 语句中last_name 是varchar类型 select * from student where last_name = 1;改进方法,使用正确的数据类型select * from student where last_name = '1';2、where 条件表达式等号左侧使用函数select * from task_table where DATE_ADD(update_time,INTERVAL 2 DAY) &lt; NOW();改进方

Python numpy广播机制_正直的善良的博客-程序员秘密

numpy 在算术运算期间采用“广播”来处理具有不同形状的 array ,即将较小的阵列在较大的阵列上“广播”,以便它们具有兼容的形状。广播是编写简短直观代码的强大工具,可以非常有效地进行计算。但是,在某些情况下,广播会为特定算法使用不必要的大量内存。在这些情况下,最好用 Python 编写算法的外循环,这也可能产生更具可读性的代码,因为使用广播的算法往往会随着广播中维度数量的增加而变得更难以解释。...

个人计算机使用的电子元器件主要是什么,晶体管计算机是第几代_个人计算机使用的电子元器件_计算机网络最突出的(28)..._米诺大魔王的博客-程序员秘密

44.能把汇编语言源程序翻译成目标程序的程序称为___D___。A)编译程序 B)解释程序 C)反汇编程序 D)汇编程序45.操作系统的功能之一是___C___。A)将高级语言的源程序编译成目标程序 B)负责诊断机器的故障C)控制和管理计算机系统各种资源的使用 D)负责外部设备与主机之间的信息交换46.《计算机软件保护条例》中所称的计算机软件是指___D___。A)计算机程序 B)源程序和目标程序...

二、文件内容解析_weixin_34419321的博客-程序员秘密

/** * Sample React Native App * https://github.com/facebook/react-native * @flow */import React, { Component } from 'react'; // 还是依赖于Rectimport { AppRegistry, // 注册 StyleSheet, // 样式 Tex...

验证图片格式_wulei4的博客-程序员秘密

var fso=new ActiveXObject(&quot;Scripting.FileSystemObject&quot;); function sh...

(四)Springboot Yaml配置文件_一起码代码的博客-程序员秘密

springboot中除了可以使用application.properties配置文件外,还可以配置后缀为yaml活yml的配置文件yml配置文件的特征:1:树状层级结构展示配置项2:配置项之间如果有关系的话需要分行空两格3:配置项如果有值的话,那么需要在:后空一格在写值表现如下:application.propertiesjdbc.driverClassName=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/sprin

随便推点

微信JSAPI支付教程_一北的博客-程序员秘密

@author StormMa @date 2017-05-23 01:41 生命不息,奋斗不止! 最近一个项目中用到了微信开发,之前没有做过支付相关的东西,算是拿这个来练练手,刚开始接触支付时候很懵逼,加上微信支付开发文档本来就讲得不清楚,我是彻底蒙圈了,参考了很多代码之后,算是有一点思路了。用户认证获取openId 如果你知识关注支付流程,这块可以跳过,因为我知道这些你已经做过了

第一天早课11.30_早课第一天心得_cui264的博客-程序员秘密

1.鼠标在windows桌面怎么进入到centos左键单击2.怎么从centos系统推出到window桌面Esc3.我们常用的linux系统有哪两种centos ubuntu4.查看当前目录命令ls5.进入到目录的命令cd6.root的家目录/root7.怎么进入到root的家目录cd /root8.波浪线代表着什么当前用户的家目录9.返回到上一层目录cd ..10.上层目录一般都怎么样展示.....

npm ERR! Failed at the ***@0.1.0 serve:`cross-env NODE_ENV=prd vue-cli-service serve`_范天缘的博客-程序员秘密

从远程拉代码下来的时候-&gt;下载依赖后-&gt;运行报错提示缺少模块,脚本运行失败,可能不是npm的问题1、:删除node_modules包,重新下载依赖2、重新运行备注:如果下载依赖报错,把代码不要放在c盘!不要放在c盘,放到其他盘在重新下依赖,运行成功...

GitHub上最火的Android开源项目(一)_github安卓项目_火山石的博客-程序员秘密

GitHub在中国的火爆程度无需多言,越来越多的开源项目迁移到GitHub平台上。更何况,基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。为此,CSDN特整理了在GitHub平台上最受欢迎的Android及iOS开源项目,以飨开发者。    下面,就让我们一起来看看,在GitHub平台上,究竟有哪些Andro

Android View 绘制流程详解_Android_FLING的博客-程序员秘密

View 绘制机制一、 View 树的绘图流程当 Activity 接收到焦点的时候,它会被请求绘制布局,该请求由 Android framework 处理.绘制是从根节点开始,对布局树进行 measure 和 draw。整个 View 树的绘图流程在ViewRoot.java类的performTraversals()函数展开,该函数所做 的工作可简单概况为是否需要重新计算视图大小(measu...

关闭linux服务器防火墙_weixin_34100227的博客-程序员秘密

--全部关闭systemctlstopfirewalld.service#停止firewallsystemctldisablefirewalld.service#禁止firewall开机启动--只开放某个端口firewall-cmd--zone=public--add-port=8070/tcp--permanent转载于:https://www.cnbl...

推荐文章

热门文章

相关标签