拼手气红包算法_线段切割法
生活随笔
收集整理的這篇文章主要介紹了
拼手气红包算法_线段切割法
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
線段切割法就是將紅包的總金額視為一段定長的長度,從中隨機(jī)切(紅包份數(shù)-1)個(gè)點(diǎn),然后依次將線段分配。
下面是python的實(shí)現(xiàn),當(dāng)出現(xiàn)相同切割點(diǎn)時(shí)重新取點(diǎn)。這個(gè)不是最好的解決相同切割點(diǎn)的方法,如果可以實(shí)現(xiàn)順序記錄每一個(gè)取到的隨機(jī)點(diǎn),后續(xù)再生成隨機(jī)點(diǎn)時(shí),取點(diǎn)的范圍中刪去這些點(diǎn),這樣應(yīng)該會(huì)更好。這個(gè)優(yōu)化后續(xù)完善。。
#!/usr/bin/python #-*- coding utf-8 -*-#使用線段切割法:將紅包總金額視為一段長度,從中隨機(jī)取人數(shù)減1個(gè)切割點(diǎn)將線段切割為等同人數(shù)的份數(shù)然后分配__author__ = 'Luo Chenyi' __data__ = '2020-12-18' __vertion__ = 'v1.00.00'import random#MANUAL_SET = True MANUAL_SET = False if MANUAL_SET == True:total_momey = int(input("Please input the amount of money:"))total_num = int(input("How many people:"))total_times = int(input("How many cycles:")) else:total_momey = int(100)total_num = int(10)total_times = int(1000)variance_exam_times = int(10)#輸出每次的搶紅包結(jié)果 #DEBUG_INF_FOR_EACH_RED_PACKET_SNATCHING = True DEBUG_INF_FOR_EACH_RED_PACKET_SNATCHING = False#輸入: # momey: 總金額 # num: 總?cè)藬?shù) # times: 總次數(shù) #返回: # variance: 進(jìn)行了times搶紅包的方差 def red_packet(money, num, times=1):if money <= 0:raise AttributeError('The amount should greater than 0.')elif num <= 0:raise AttributeError('The num should greater than 0.')#參數(shù)初始化和定義current_money = money * 100 #當(dāng)前剩余的錢,初始值為money,乘100倍表示精確到分avg = (current_money * times)/ num #平均每人搶到的總金額 = 總金額 / 總?cè)藬?shù)variance = 0 #方差, 用1000次紅包的總金額來計(jì)算方差,方差越小,表示越公平circle_times = 0 #循環(huán)次數(shù)L = [] #定義一個(gè)空表,記錄每個(gè)人搶到的紅包金額CutPoint = [] #定義一個(gè)空表,記錄線段的切割點(diǎn)for i in range(0, num):L.append(0)while circle_times < times:circle_times += 1if DEBUG_INF_FOR_EACH_RED_PACKET_SNATCHING == True:#輸出本次搶紅包結(jié)果print('********************************************')print('Number of red packets snatched: %d' %circle_times)#切割點(diǎn)生成和排序,分num份則切(num-1)個(gè)點(diǎn)if num == 1:CutPoint = [0]else:#生成切割點(diǎn)CutPoint = list(set([random.randint(1, current_money - 1) for i in range(num - 1)]))while len(CutPoint) != num - 1:#有相同切割點(diǎn)則重新生成切割點(diǎn)CutPoint = list(set([random.randint(1, current_money - 1) for i in range(num - 1)]))#切割點(diǎn)按從小到大排列CutPoint.sort()if DEBUG_INF_FOR_EACH_RED_PACKET_SNATCHING == True:print('Length of CurPoint : %d' %len(CutPoint))print('CurPoint is :', CutPoint)for i in range(0, num - 1):if i == 0:amount_of_i = CutPoint[i]else:amount_of_i = CutPoint[i] - CutPoint[i - 1]L[i] += amount_of_iif DEBUG_INF_FOR_EACH_RED_PACKET_SNATCHING == True:print(' id[%d] get %.02f' %(i + 1, (float)(amount_of_i / 100)))amount_of_i = current_money - CutPoint[num - 2]L[num - 1] += amount_of_iif DEBUG_INF_FOR_EACH_RED_PACKET_SNATCHING == True:print(' id[%d] get %.02f' %(num, (float)(amount_of_i / 100)))#輸出多次搶紅包的最終結(jié)果current_money = 0variance = 0print('********************************************')print(' Total money is %d, for %d people, circle %d times' %(money, num, times))print(' Total amount of red packets %.02f' %(money * times))print(' Average value is %.02f' %(float)(avg / 100))for i in range(0, num):current_money += L[i]variance += pow(abs((L[i] - avg) / times), 2)print(' id[%d] totally get %.02f average each time %.02f' %(i + 1, (float)(L[i] / 100), (float)(L[i] / 100 / times)))variance = (float)(variance / num / 10000)print(' The variance : %.2f' %variance)print(' Total amount of received : %.2f' %(current_money / 100))if (money * times) != (current_money / 100):raise AttributeError('Total amount of red packets(%.02f) is not equal to total amount of received(%.02f)' %(money * times, current_money / 10))print('********************************************')return (int)(variance * 100)if __name__ == '__main__':variance_sum = 0for i in range(variance_exam_times):variance_sum += red_packet(total_momey, total_num, total_times)print('Sum of all variance exam(%d times) is %.02f' %(variance_exam_times, (float)(variance_sum / 100)))print('Done')總結(jié)
以上是生活随笔為你收集整理的拼手气红包算法_线段切割法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++笔记-学习算法与实现-计算几何-二
- 下一篇: 基础49 卖鸭子