解决需求:游戏商城盲盒礼包概率计算

过年游戏公司提出要在商店出一个随机礼包,里面有不同价值的奖品,但最后的期望价值等于礼包价格,相当于计算一元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]))  

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值