拼手气红包算法_线段切割法
生活随笔
收集整理的這篇文章主要介紹了
拼手气红包算法_线段切割法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
線段切割法就是將紅包的總金額視為一段定長的長度,從中隨機切(紅包份數-1)個點,然后依次將線段分配。
下面是python的實現,當出現相同切割點時重新取點。這個不是最好的解決相同切割點的方法,如果可以實現順序記錄每一個取到的隨機點,后續再生成隨機點時,取點的范圍中刪去這些點,這樣應該會更好。這個優化后續完善。。
#!/usr/bin/python #-*- coding utf-8 -*-#使用線段切割法:將紅包總金額視為一段長度,從中隨機取人數減1個切割點將線段切割為等同人數的份數然后分配__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)#輸出每次的搶紅包結果 #DEBUG_INF_FOR_EACH_RED_PACKET_SNATCHING = True DEBUG_INF_FOR_EACH_RED_PACKET_SNATCHING = False#輸入: # momey: 總金額 # num: 總人數 # times: 總次數 #返回: # variance: 進行了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.')#參數初始化和定義current_money = money * 100 #當前剩余的錢,初始值為money,乘100倍表示精確到分avg = (current_money * times)/ num #平均每人搶到的總金額 = 總金額 / 總人數variance = 0 #方差, 用1000次紅包的總金額來計算方差,方差越小,表示越公平circle_times = 0 #循環次數L = [] #定義一個空表,記錄每個人搶到的紅包金額CutPoint = [] #定義一個空表,記錄線段的切割點for i in range(0, num):L.append(0)while circle_times < times:circle_times += 1if DEBUG_INF_FOR_EACH_RED_PACKET_SNATCHING == True:#輸出本次搶紅包結果print('********************************************')print('Number of red packets snatched: %d' %circle_times)#切割點生成和排序,分num份則切(num-1)個點if num == 1:CutPoint = [0]else:#生成切割點CutPoint = list(set([random.randint(1, current_money - 1) for i in range(num - 1)]))while len(CutPoint) != num - 1:#有相同切割點則重新生成切割點CutPoint = list(set([random.randint(1, current_money - 1) for i in range(num - 1)]))#切割點按從小到大排列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)))#輸出多次搶紅包的最終結果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')總結
以上是生活随笔為你收集整理的拼手气红包算法_线段切割法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++笔记-学习算法与实现-计算几何-二
- 下一篇: 基础49 卖鸭子