遇到一个需求,某网站为了吸引人气,要开展抽奖活动,需求主要有以下几点:
1.共分一、二、三等奖,要控制一等奖尽量不要一开始就抽掉;
2.活动长期开展,持续时间一周左右,要使每天的各奖项概率趋于一致;
3.为保证每天活动参与人数,要确保在限定人数附近抽出所有奖项;
基于以上几点,做出如下设计:
1.首先要输入天预估总人数,并将奖品平均分到每天,得到各奖项的日均奖品数(可能为小数);
2.计算各奖项的抽奖概率,日均奖品数/日抽奖总人数;
3.产生一个随机双精度数,若小于等于概率则视为抽中;
4.一次抽奖开始时,先抽取三等奖,若中奖则提示,若不中奖则继续抽取二等奖,若再不中奖则抽取一等奖;
5.每次抽奖过后,若抽中奖品则预估总人数-1,并且所有概率重新计算,并应用于下一轮抽奖;
6.若总人数小于一个限定阀值,则停止概率变化,用此概率完成全部抽奖;
7.当天奖品总数小于1时,抽奖结束,小数部分流入后一天继续抽奖。
大概思路如上,设计较为简单,没有技术含量,会有的问题就是理论上后一天一开始抽奖的概率会偏高一些,也曾想用某些数学公式定理来解决,但因为对概率论不了解,不了了之。
顺手贴上第一天所有抽奖的代码,希望感兴趣的朋友多给些宝贵意见!
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using System.Threading; namespace Lottery { class Program { private static string InputString;//输入字符串 private static int LevelCount;// private static int DayNum;// private static int DayUserNum;// private static int[] arrPrizeNum;// private static double[] AvgPrizeNum; private static double TotalPrizeNum; private static double[] ArProbability; public static Random rand = new Random((int)DateTime.Now.Ticks); static void Main(string[] args) { ShowInfo(); GetInputNum("请输入奖项总数:", ref LevelCount); arrPrizeNum = new int[LevelCount]; InputPrizeNum(); GetInputNum("请输入预计抽奖天数:", ref DayNum); GetInputNum("请输入第一天预估总人数:", ref DayUserNum); BeginLottery(); } private static void ShowInfo() { Console.WriteLine("欢迎使用随机抽奖系统!"); } private static void InputPrizeNum() { for (int i = 0; i < LevelCount; i++) { GetInputNum("请输入 " + (i + 1) + " 等奖奖品数目:", ref arrPrizeNum[i]); } } private static void GetInputNum(string words, ref int target) { while (true) { Console.WriteLine(words); InputString = Console.ReadLine(); int temp = SafeParse(InputString); if (temp != -1) { target = temp; break; } else { Console.WriteLine("您的输入有误,请输入整型数字!"); continue; } } } private static int SafeParse(object obj) { int temp; if (!int.TryParse(obj.ToString(), out temp)) { temp = -1; } return temp; } private static void BeginLottery() { AvgPrizeNum = new double[LevelCount]; ArProbability = new double[LevelCount]; TotalPrizeNum = 0; for (int i = 0; i < LevelCount; i++) { TotalPrizeNum += arrPrizeNum[i]; } for (int i = 0; i < LevelCount; i++) { AvgPrizeNum[i] = (double)arrPrizeNum[i] / (double)DayNum; } for (int i = 0; i < LevelCount; i++) { ArProbability[i] = (double)AvgPrizeNum[i] / (double)DayUserNum; } for (int j = 0; j < 10000; j++) { double x = rand.NextDouble(); for (int i = LevelCount - 1; i >= 0; i--) { if (x < ArProbability[i]) { if (AvgPrizeNum[i] > 1) { AvgPrizeNum[i]--; Console.WriteLine("恭喜您,抽到了" + (i + 1) + "等奖!"); LotteryOnit(); //Console.ReadLine(); break; } else { continue; } } else { Console.WriteLine("很遗憾,欢迎下次再来!" + DayUserNum); x = rand.NextDouble(); LotteryOnit(); continue; } } if (DayUserNum > TotalPrizeNum / DayNum) { DayUserNum--; } for (int i = 0; i < AvgPrizeNum.Length; i++) { if (AvgPrizeNum[i] >1) { break; } if (i == AvgPrizeNum.Length - 1) { Console.WriteLine("共" + j + "位用户参与," + "奖已抽完!"); Console.ReadLine(); } } Console.WriteLine(); } Console.ReadLine(); } private static void LotteryOnit() { for (int i = 0; i < LevelCount; i++) { ArProbability[i] = (double)AvgPrizeNum[i] / (double)DayUserNum; Console.WriteLine("第"+(i+1)+"等奖的概率变为:"+ArProbability[i].ToString()); Console.WriteLine(AvgPrizeNum[i] + " " + DayUserNum); } } } }