过年游戏公司提出要在商店出一个随机礼包,里面有不同价值的奖品,但最后的期望价值等于礼包价格,相当于计算一元N次不定方程,一个方程求N个未知数的数值计算
开始有点懵,后来用Python写了一下还是解决了,具体算法如下:
比如说n为有5个物品价格的列表,target是盲盒的价格
n里面数值比target贵的分一类为ll,便宜的分一类为sl,
然后用二分法设两个随机数lrand, srand在其中列表的最大和最小值中间随机,作为每个类里面的期望价格(平均值)
x为便宜一类需要占总价值的比率
sub_ll为贵列表的平均数,sub_sl为便宜列表的平均数,
如果便宜列表的平均数离期望值更远,而且便宜列表的数量也比贵列表里物品数量多,那么就得重新开始随机了,因为这时候价格肯定很低于期望值,相当于平衡倒向一边,如果一边列表的平均价格离期望值远,但里面奖品数量比另一边小,那么我们就觉得有戏了
当然这个算法核心是二分法,递归直到物品都遍历完,并且概率都算出来程序才会结束,所以第一层我们会算出比target大的列表和比起小的列表所占比率,看他们的期望值是不是target,如果成功进入第二层我们再从2个列表里面再一刀切,算出其中比lrand,srand大的列表和比起小的列表所占比率,否则将在当前递归层继续随机,直到满足我们想要的随机数,当然每一层二分都会将改变x1, x2的状态。
count_sum将输出x1,x2并打印出我们想要的结果和得出各个物品的概率,并以图表显示
python代码如图,list1为5个盲盒里面的物品价格列表,list2是他们的期望价格,以后要算宝箱礼盒概率的时候可以直接用。
# -*- coding: utf-8 -*-
"""
Spyder Editor
This is a temporary script file.
"""
import random
import seaborn as sns
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"C:\Windows\Fonts\simhei.ttf", size=14)
xl = []
def keyfind(key, index, list1):
for i in range(len(list1)):
if key == list1[i][index-1]:
return list1[i][index]
return False
def count_sum(xl, n, target):
sum1 = 0
list1_sum = []
sum2 = 0
for i in range(len(xl)):
if xl[i][0][0] == xl[i][0][1]:
list1_sum.append([xl[i][0][1], xl[i][1]])
print([xl[i][0][1],":rate =",xl[i][1]])
sum1 += xl[i][1]
print("rate_sum:",sum1)
for j in range(len(list1_sum)):
sum2 += list1_sum[j][1] * list1_sum[j][0]
print("price_sum:",sum2)
#=====正态====
print(list1_sum)
list1_sum.sort()
list2_sum = [j for [i,j] in list1_sum]
list3_sum = [i for [i,j] in list1_sum]
mid = len(list1_sum) // 2
if list1_sum[mid] > list1_sum[0]:
if max(list2_sum) - min(list2_sum) < 0.5 and min(list2_sum) > 0.005:
print(list1_sum)
plt.bar(list3_sum, list2_sum , label='graph 1')
# params
# x: 条形图x轴
# y:条形图的高度
# width:条形图的宽度 默认是0.8
# bottom:条形底部的y坐标值 默认是0
# align:center / edge 条形图是否以x轴坐标为中心点或者是以x轴坐标为边缘
plt.legend()
plt.xlabel('price')
plt.ylabel('rate')
plt.title(u'测试例子——条形图', FontProperties=font)
#曲线
plt.show()
xl = []
else:
test(n,target)
count_sum(xl,n,target)
else:
test(n,target)
count_sum(xl,n,target)
print(list1_sum)
# plt.bar(list3_sum, list2_sum , label='graph 1')
#
#
# # params
#
# # x: 条形图x轴
# # y:条形图的高度
# # width:条形图的宽度 默认是0.8
# # bottom:条形底部的y坐标值 默认是0
# # align:center / edge 条形图是否以x轴坐标为中心点或者是以x轴坐标为边缘
#
# plt.legend()
#
# plt.xlabel('price')
# plt.ylabel('rate')
#
# plt.title(u'测试例子——条形图', FontProperties=font)
#
# plt.show()
#
def test( n,target):
print("n:",n,"target",target)
ll = [i for i in n if i > target]
sl = [i for i in n if i <= target]
lrand = random.uniform(min(ll),max(ll))
srand = random.uniform(min(sl),max(sl))
x = (target - srand )/(lrand -srand)
#=====接近target的比重大===
sub_ll = abs(target - sum(ll)/len(ll))
sub_sl = abs(sum(sl)/len(sl) - target)
print("sub_ll:",sub_ll)
print("sub_sl :",sub_sl)
if sub_ll < sub_sl:
if x < len(ll)/len(n):
test(n, target)
else:
result = keyfind([min(n),max(n)],1, xl),
if keyfind([min(n),max(n)],1, xl):
[x2] = result
else:
x2 = 1
print("x2",x2)
if srand * (1- x) + lrand*x == target :
if x2 == 1 :
xl.append(([min(sl),max(sl)],(1-x)))
xl.append(([min(ll),max(ll)],x))
else:
xl.append(([min(sl),max(sl)],(1-x)*x2))
xl.append(([min(ll),max(ll)],x2*x))
print("xl",xl," ",(1-x)*x2)
if len(ll) > 1:
test(ll,lrand)
if len(sl) > 1:
test(sl,srand)
print(lrand)
print(srand)
print(x)
else:
test(n,target)
else:
print("x:",x)
if x > len(ll)/len(n):
test(n, target)
else:
result = keyfind([min(n),max(n)],1, xl),
if keyfind([min(n),max(n)],1, xl):
[x2] = result
else:
x2 = 1
print("x2",x2)
if target+1 > srand * (1- x) + lrand*x >= target -1 :
if x2 == 1 :
xl.append(([min(sl),max(sl)],(1-x)))
xl.append(([min(ll),max(ll)],x))
else:
xl.append(([min(sl),max(sl)],(1-x)*x2))
xl.append(([min(ll),max(ll)],x2*x))
print("xl",xl," ",(1-x)*x2)
if len(ll) > 1:
test(ll,lrand)
if len(sl) > 1:
test(sl,srand)
print(lrand)
print(srand)
print(x)
else:
test(n,target)
def keyfind1(key, index, list1):
a = keyfind(key, index, list1)
return a
list1 = [[30,50,20,16,10],[79,80,100,128,139],[89,168,198,200.000001,200,268],[218,229,249,288,251,300.000001,300,368],[200,300.00001,300,359,380,388,399.00001,399,400,500]]
list2 = [18,88,188,288,388]
list_price = [ 79,80,100,128,139]
print(test(list1[2],list2[2]))
print(count_sum(xl, list1[2], list2[2]))