到一個需求,某網站為了吸引人氣,要開展抽獎活動,需求主要有以下幾點:
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);
}
}
}
}