背景
最近想到一个有趣的现象:羊城通在使用15次后才有优惠,到底前15次是否需要尽快使用低价进行刷次数?刷多少次后才是最优惠的?
针对以上两个问题,使用python进行计算,看看结果时怎样的?!
注:本算法只适应于当月乘坐地铁固定次数出行(即每月正常上下班路程次数与费用),对于不确定次数的不适用
算法实现:本算法用于实现工薪阶级,每月固定乘坐公交地铁上下班,计算每月最优惠出行费用
难点:在使用羊城通过程中,我们可以很容易就算出不使用刷卡次数当月的费用;但在使用刷卡次数后,每次刷卡后,总费用都存在变化;到底刷卡几次的总费用时最低的呢?
针对这个难点:
我们需要将这两种情况分别列举出来:
(1)当月不使用刷卡次数,即
总费用 = 15*一趟行程费用(打折前)+(当月出行次数-15)*一趟行程费用(打折后)
注:当月出行次数指的是一次乘坐地铁
(2)当月使用1—15次刷卡次数,即
总费用 = 刷卡次数 * 1.9 +(15 - 刷卡次数)*一趟行程费用(打折前)+(当月出行次数-15+i)*一趟行程费用(打折后)
注:公式中的1.9是广州地铁同站进出使用羊城通支付的最低费用,即刷次数当然就是选择最低费用进行
当我们明确算法时,我们就可以进行程序的编写了。
为了方便我们查看,这里我们引入matplotlib库生成折线图,方便查看
import numpy as np
from matplotlib import pyplot as plt
为了方便每人根据自己的情况查询,设置为手动输入当月出行次数、一趟行程费用(打折前)、一趟行程费用(打折后)的数据:
这里以我的情况为例:按工作日出行,记每月22个工作日,即每月出行次数:44次(来回),一趟行程费用(打折前):5.7元,一趟行程费用(打折后):3.6元
#输入当月出行次数
print('输入当月出行次数:')
trip_num = int(input())
#输入一趟行程费用(打折前)
print('输入一趟行程费用(打折前):')
trip_fee = float(input())
#输入一趟行程费用(打折后)
print('输入一趟行程费用(打折后):')
trip_fee_discnt = float(input())
为了方便查看曲线变化,引用matplotlib库生成折线图
#声明全局变量
sum_trip_fee=0 #当月出行花费
sumMax_trip_fee=0 #当月出行最大花费
#定义一个函数,出行次数大于15则使用另一函数M
def function(x, x1, x2): # x1是分段点位置
if x <= x1:
return x * trip_fee
elif x <= x1 < x2:
x1 * 1.9 + (x2 - x1) * trip_fee + (x - 15 + x2) * trip_fee_discnt
else:
return 15 * trip_fee + (x - 15) * trip_fee_discnt
#根据次数进行函数计算
#当月正常使用,不进行刷次数操作所花费用
if trip_num <= 15:
#如果当月乘坐地铁次数小于等于15次,生成函数图像
sum_trip_fee = trip_num * trip_fee
x = np.arange(0, 100, 1) #生成等差数组
y = trip_num * x
plt.xlabel('出行次数:x')
plt.ylabel('出行费用:y')
plt.title("出行次数与费用函数")
plt.plot(x, y)
plt.ylim(0, trip_num * trip_fee) #限制y的范围
plt.xlim(0, trip_num) #限制x的范围
plt.show()
print('当月出行花费:'+str(sum_trip_fee))
sumMax_trip_fee = sum_trip_fee
else:
#当月乘坐地铁次数大于15次
sum_trip_fee = 15 * trip_fee +(trip_num-15)*trip_fee_discnt
x = np.arange(0, 100, 1) #生成等差数组
y = np.array([function(t, 0, 15) for t in x]) #根据x计算各点函数值
plt.xlabel('出行次数:x')
plt.ylabel('出行费用:y')
plt.title("出行次数与费用函数")
plt.plot(x, y)
plt.ylim(0, trip_num * trip_fee) #限制y的范围
plt.xlim(0, trip_num) #限制x的范围
plt.show()
print('当月出行花费:'+str(sum_trip_fee))
sumMax_trip_fee = sum_trip_fee
按当月不使用刷卡次数,得到当月出行花费:189.9元
接下来,就需要将当月使用1—15次刷卡次数,得到的当月出行花费计算出来:
#进行刷卡费用
#进行循环比较,得出费用最好的刷卡数
num_swip = {}
num_swips = {}
num_swip.update({0: sum_trip_fee})
for i in range(1,16):
if i <= 15:
if trip_num + i <= 15:
sum_trip_fee = i * 1.9 + trip_num * trip_fee
num_swip.update({i: sum_trip_fee})
else:
sum_trip_fee = i * 1.9 +(15 - i)*trip_fee +(trip_num-15+i)*trip_fee_discnt
num_swip.update({i: sum_trip_fee})
print('当月刷卡次数:{0}次,出行花费{1}元'.format(str(i),str(sum_trip_fee)))
i+=1
最后,我们只需要将刷卡次数与当月出行花费存入到字典中,取出花费最少的值对于的刷卡次数,即可获取到当月刷卡次数多少次可得到当月出行最少花费
#自定义函数
def getKey(dic, value):
if value not in dic.values():
return None
result = []
for key in dic:
if dic[key]==value:
result.append(key)
return result
#当月出行最大费用(即不使用刷卡次数的费用)
print('当月出行最大费用:'+str(sumMax_trip_fee))
#取出费用最少的刷卡次数
minValue=min(num_swip.values())
print('当月出行最少费用:'+str(minValue))
result = getKey(num_swip,minValue)
print('当月需刷卡次数:'+str(result[0]))
print('当月刷卡{0}次省了{1}块钱:'.format(str(result[0]),str(sumMax_trip_fee-minValue)))
if result[0] == 0:
print('当月刷卡1次可省-1.9块钱)')
else:
print('当月刷卡1次可省{0}块钱:'.format((sumMax_trip_fee-minValue)/result[0]))
最后的话:
通过这次的计算,我发现这个出行费用与出行次数与行程费用密切相关,当出行费用越大时,刷卡才有效,否则一味的刷卡,可能还不如不刷卡花费少;但有一个小窍门:当你的行程费用(打折前)与行程费用(打折后)金额大于你刷卡的金额,且你当月的出行次数大于15次时,你刷卡才不会亏!!!
注:本次算法经过少量数据验证可行,未对全部场景进行验证,如有遗漏,欢迎指教!!!