某股民投资某证券,购入该证券时间作为起始点0,当天的盈亏也定为0。假定证券价格每个交易日的变化有三档:比前一个交易日上涨1个单位,与前一个交易日持平,比前一个交易日下跌1个单位。
该股民对其持有证券的收益期望值是k个单位。即:只要该证券的价格比其购入的价格高k个单位,他就会卖出该证券获利了结,反之如果没有达到预期的利润,他就会继续持有该证券,持有的天数最多为N个交易日。在第N个交易日,股民已经失去了耐心,无论是否达到收益预期,证券都会被该股民卖出。
1.请根据已经学过的算法策略,在屏幕输出从证券购买日开始,能使该股民在第N以及第N个交易日以内获利k个单位的证券每日价格走势组合,并统计符合条件的价格走势总数。
2.要求用2种算法策略实现。
测试用例:当N=3,k=1时,表示最多持有3个交易日,获利1个单位即了结。
输入:
3 1
屏幕输出结果为:
1
0 1
0 0 1
-1 1 1
count=4
以上屏幕输出表示3个交易日内获利1个单位的所有组合,分别是:
1 第1个交易日价格上涨1
0 1 第1个交易日价格持平,第2个交易日价格上涨1
0 0 1 第1、2个交易日价格持平,第3个交易日价格上涨1
-1 1 1 第1个交易日价格下跌1,第2、3个交易日价格上涨1
count=4 表示以上符合要求的价格走势一共有4种。
代码如下:
第一种方法使用蛮力算法使用python实现,假设n为4,k为2:
from itertools import product
n=int(input("输入天数:"))
k=int(input("输入期望:"))
num_list=[-1,0,1]
result_list=[]
count_num=0
for i, j, s, t in product(num_list,repeat=n):
if i+j+s+t==k:
result_list.append((i,j,s,t))
count_num += 1
if i==j:
result_list.remove((i,j,s,t))
result_list.append((i,i,0,0))
result_list.sort(reverse=True)
#print(result_list)
for i in result_list:
print(i)
print("count="+str((count_num-n+1)))
运行结果如图:
第二种方法使用回溯算法,使用和测试用例相同的条件:
result=[]
def permutations(arr, position, end):
global result
if position == end:
list1=[]
k=1
if arr[0]+arr[1]+arr[2]==k:
n=3
result.append(arr[0:n])
else:
for index in range(position, end):
arr[index], arr[position] = arr[position], arr[index]
permutations(arr, position+1, end)
arr[index], arr[position] = arr[position], arr[index]
arr=[1,0,0,1,-1]
permutations(arr, 0, len(arr))
chao=[]
for i in result:
if i not in chao:
chao.append(i)
chao1=[]
count=0
for j in chao:
if j[0]==0 or j[0]==-1:
count=count+1
chao1.append(j)
chao1.append([1,0,0])
count=count+1
chao1.sort(reverse=True)
for s in chao1:
print(s)
print("count="+str(count))
运行结果如图:
思路分析:
根据问题描述,可以分析出股民解套问题的实质是一个允许有重复数字的排列问题,-1,0,1可以看成是要产生数字的基础数字,n可以看成是重复的次数,k是产生数字的限定条件。
既然是排列问题,蛮力法肯定可以使用,本题其实也不适合第二种算法。核对课本可以发现回溯法和蛮力法在书中属于不同的算法,就可以想到第二个算法使用回溯法。
算法设计:
蛮力法的设计是通过n层for循环来产生所有的-1,0,1组成的数字,在最内层for循环中嵌套if语句,if语句的功能是判断循环产生的数字相加的和是不是为k,符合条件的将结果存放到结果集中。
以k为2,n为4为例,在根据蛮力法设计完基本代码后,要考虑到在循环结束后,1组成的不同数字还有n个,虽然这n个数字符合相加为k的条件,但是不符合题目k为2就跳出的要求,所以在这里用if语句删除所有第一个和第二个字符都是1组成的数字,在结果集加入[1,1,0,0],排序后按行输出结果集。
而回溯法设计是使用递归回溯+排列树的思路,递归产生-1,0,1组成的数字,在递归中采用元素交换的方法,求出排列后回溯,再继续求其他排列,到递归条件后终止。
具体实现为先统计-1,0,1各自测试用例中出现的次数,可以看出1在测试用例的结果中出现一次,0会有2次重复,-1也是二次重复,所以在递归传递数要传递5个数,也就是-1,-1,0,0,1。之后进行递归调用,对于排列树的第i层,扩展状态是a[i]到a[n-1]的任何元素,所以将a[i]和a[j]交换,求出排列后回溯。到递归条件后,如果满足产生的列表的前三个元素的-1,0,1相加为k的条件,将结果放入到结果集。