網站首頁 編程語言 正文
二倍均值法(公平版)?
發出一個固定金額的紅包,由若干個人來搶,需要滿足哪些規則?
1.所有人搶到金額之和等于紅包金額,不能超過,也不能少于。
2.每個人至少搶到一分錢。
3.要保證所有人搶到金額的幾率相等。
假設剩余紅包金額為M,剩余人數為N,那么有如下公式:
每次搶到的金額 = 隨機區間 (0, M / N × 2)
這個公式,保證了每次隨機金額的平均值是相等的,不會因為搶紅包的先后順序而造成不公平。舉個例子:
假設有10個人,紅包總額100元。100/10×2 = 20, 所以第一個人的隨機范圍是(0,20 ),平均可以搶到10元。
假設第一個人隨機到10元,那么剩余金額是100-10 = 90 元。90/9×2 = 20, 所以第二個人的隨機范圍同樣是(0,20 ),平均可以搶到10元。
假設第二個人隨機到10元,那么剩余金額是90-10 = 80 元。80/8×2 = 20, 所以第三個人的隨機范圍同樣是(0,20 ),平均可以搶到10元。
以此類推,每一次隨機范圍的均值是相等的。
static void Main(string[] args) { for (int i = 0; i < 10; i++) { var list = DivideRedPackage(100* 100, 10); Console.WriteLine(string.Join(",", list)); int count = 0; foreach (var item in list) { count += item; } Console.WriteLine(count); } System.Console.ReadKey(); } ////// 產生紅包數組 /// /// 紅包總金額,單位分 /// 紅包人數 ///static List DivideRedPackage(int cashCount, int peopleNumber) { List redPackageList = new List (); if (cashCount <= peopleNumber) { for (int i = 0; i < cashCount; i++) { redPackageList.Add(1); } return redPackageList; } Random random = new Random(GetRandomSeed()); int restCash = cashCount, restPeople = peopleNumber; for (int i = 0; i < peopleNumber - 1; i++) { var cash = random.Next(1, restCash / restPeople * 2); restCash -= cash; restPeople--; redPackageList.Add(cash); } redPackageList.Add(restCash); return redPackageList; }
例如,產生的結果如下:
1960,189,234,1763,1211,1236,1340,53,1652,362
10000
1032,1380,456,1885,608,857,1541,452,1273,516
10000
976,955,749,936,1990,1177,781,325,527,1584
10000
794,935,272,216,2034,522,455,2313,2260,199
10000
1376,1539,1292,614,443,1874,889,544,821,608
10000
914,15,877,1738,604,932,321,983,3106,510
10000
659,791,800,1066,788,908,991,2473,495,1029
10000
1256,733,1385,667,1192,1237,455,105,2121,849
10000
1941,1173,567,1280,1558,618,183,644,133,1903
10000
1313,735,1198,1173,1288,522,1879,1155,59,678
10000
上述示例中需注意,Random是一個偽隨機數生成器,在大多數 Windows 系統上,Random 類 (System) | Microsoft Docs 15 毫秒內創建的對象可能具有相同的種子值。因此,如果New Random在循環中使用,就必須提供隨機的種子值。我們可以使用RNGCryptoServiceProvider 類 (System.Security.Cryptography) | Microsoft Docs類產生隨機樹種子。具體代碼如下:
////// 產生加密的隨機數種子值 /// ///static int GetRandomSeed() { byte[] bytes = new byte[4]; System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider(); rng.GetBytes(bytes); return BitConverter.ToInt32(bytes, 0); }
線段切割法(手速版)?
算法思路如下:
線段分割法就是把紅包總金額想象成一條線段,而每個人搶到的金額,則是這條主線段所拆分出的子線段。
當N個人一起搶紅包的時候,就需要確定N-1個切割點。
因此,當N個人一起搶總金額為M的紅包時,我們需要做N-1次隨機運算,以此確定N-1個切割點。
隨機的范圍區間是(1, M)。當所有切割點確定以后,子線段的長度也隨之確定。這樣每個人來搶紅包的時候,只需要順次領取與子線段長度等價的紅包金額即可。
需要注意一下兩點:
1.每個人至少搶到一分錢。
2.分割的線段如果重復需要重新切割
具體代碼如下:
class Program { static ListDivideRedPackage(int cashCount, int peopleNumber) { List redPackageList = new List (); if (cashCount <= peopleNumber) { for (int i = 0; i < cashCount; i++) { redPackageList.Add(1); } return redPackageList; } Random random = new Random(GetRandomSeed()); int restPeople = peopleNumber; List lineList = new List (); while (restPeople > 1) { var line = random.Next(1, cashCount); if (lineList.Contains(line) == false) { lineList.Add(line); restPeople--; } } lineList.Sort(); redPackageList.Add(lineList[0]); for (int i = 0; i < peopleNumber - 2; i++) { var cash = lineList[i + 1] - lineList[i]; redPackageList.Add(cash); } redPackageList.Add(cashCount - lineList[lineList.Count - 1]); return redPackageList; } static int GetRandomSeed() { byte[] bytes = new byte[4]; System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider(); rng.GetBytes(bytes); return BitConverter.ToInt32(bytes, 0); } static void Main(string[] args) { for (int i = 0; i < 10; i++) { var list = DivideRedPackage(100 * 100, 10); Console.WriteLine(string.Join(",", list)); int count = 0; foreach (var item in list) { count += item; } Console.WriteLine(count); } System.Console.ReadKey(); } }
輸出結果如下:
409,2233,1843,546,983,679,1621,460,369,857
10000
50,472,281,603,577,1007,3929,38,591,2452
10000
194,1241,675,209,3507,1714,1199,596,313,352
10000
2127,578,16,2413,1332,586,91,260,465,2132
10000
1015,1421,963,626,3031,955,171,1112,60,646
10000
118,352,1062,1128,8,374,1879,1707,1755,1617
10000
2805,592,391,90,1468,392,2201,40,1426,595
10000
145,251,2910,59,1065,235,2761,997,1564,13
10000
814,1725,1886,39,696,202,44,992,3099,503
10000
828,1281,2402,579,380,2246,154,855,564,711
10000
原文鏈接:https://www.cnblogs.com/dongweian/p/15985941.html
相關推薦
- 2022-07-24 .Net行為型設計模式之職責鏈模式(Chain?of?Responsibility)_基礎應用
- 2022-10-30 Android?Studio調試Gradle插件詳情_Android
- 2022-10-14 matlab非線性最小二乘擬合
- 2024-03-04 echarts 柱狀圖,單獨一根柱子根據條件改變顏色
- 2022-09-05 Golang中的Interface詳解_Golang
- 2022-03-09 C語言直接插入排序算法介紹_C 語言
- 2024-01-06 SpringBoot3集成RocketMQ
- 2022-05-06 python使用xlrd模塊讀取excel的方法實例_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支