using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace testDemo1
{ /// <summary> /// Red envelope algorithm, the fluctuation ratio is between 0-1 /// </summary> class Program {
static void Main(string[] args) { Program p = new Program(); //When allocating the amount, be sure to pay attention to the reasonable planning of the total amount, the amount distributed and the maximum amount List<decimal> lists = p.createBonusList(500,500,decimal .Parse("0.01"),10,decimal.Parse("0.5")); decimal Count = 0; foreach (var item in lists) { Count += item; Console.WriteLine(item); } Console.WriteLine( "Total:"+Count); }
Random ra = new Random();
/// <summary>
/// Generate a red envelope one-time distribution result·Main method entry
/// </summary>
/// <param name="totalBonus">totalBonus</param>
/// <param name="totalNum ">totalNum</param>
/// <param name="rdMin"></param>
/// <param name="rdMax"></param>
/// <param name="bigRate">specify big Probability of range interval</param>
/// <returns></returns>
public List<decimal> createBonusList(decimal totalBonus, decimal totalNum, decimal rdMin, decimal rdMax, decimal bigRate)
{ decimal sendedBonus = 0; decimal sendedNum = 0 ; List<decimal> bonusList = new List<decimal>(); while (sendedNum < totalNum)
{
decimal bonus = randomBonusWithSpecifyBound(totalBonus, totalNum, sendedBonus, sendedNum, rdMin, rdMax, bigRate);
bonus = Convert.ToDecimal(bonus.ToString("#0.00"));
bonusList.Add(bonus);
sendedNum++;
sendedBonus += bonus;
}
return bonusList;
}
/// <summary>
/// 随机分配第n个红包
/// </summary>
/// <param name="totalBonus"></param>
/// <param name="totalNum"></param>
/// <param name="sendedBonus"></param>
/// <param name="sendedNum"></param>
/// <param name="rdMin"></param>
/// <param name="rdMax"></param>
/// <param name="bigRate">平衡度0-1</param>
/// <returns></returns>
private decimal randomBonusWithSpecifyBound(decimal totalBonus, decimal totalNum, decimal sendedBonus,
decimal sendedNum, decimal rdMin, decimal rdMax, decimal bigRate)
{
decimal avg = totalBonus / totalNum; // mean
decimal leftLen = avg --rdMin;
decimal rightLen = rdMax --avg;
decimal boundMin = 0, boundMax = 0;
// Set a small probability in a large range
if (leftLen.Equals(rightLen))
{ boundMin = Math.Max((totalBonus-sendedBonus-(totalNum-sendedNum-1) * rdMax), rdMin); boundMax = Math.Min((totalBonus -sendedBonus-(totalNum-sendedNum-1) * rdMin), rdMax); } else if (rightLen.CompareTo(leftLen)> 0) { // upper limit deviation decimal standardRdMax = avg + leftLen; // right symmetric upper limit point decimal _rdMax = canReward(bigRate)? rdMax: standardRdMax; boundMin = Math.Max((totalBonus-sendedBonus-(totalNum-sendedNum-1) * standardRdMax), rdMin);
boundMax = Math.Min((totalBonus - sendedBonus - (totalNum - sendedNum - 1) * rdMin), _rdMax);
}
else
{
// 下限偏离
decimal standardRdMin = avg - rightLen; // 左侧对称下限点
decimal _rdMin = canReward(bigRate) ? rdMin : standardRdMin;
boundMin = Math.Max((totalBonus - sendedBonus - (totalNum - sendedNum - 1) * rdMax), _rdMin);
boundMax = Math.Min((totalBonus - sendedBonus - (totalNum - sendedNum - 1) * standardRdMin), rdMax);
}
// sent average offset correction-dynamic scale
if (boundMin.Equals(boundMax))
{ return getRandomVal(boundMin, boundMax); } decimal currAvg = sendedNum == 0? Avg: (sendedBonus / sendedNum); // current Sent average decimal middle = (boundMin + boundMax) / Convert.ToDecimal(2.0); decimal subMin = boundMin, subMax = boundMax; // expected value decimal exp = avg-(currAvg-avg) * sendedNum / (totalNum-sendedNum) ; if (middle> exp) { subMax = Math.Round((boundMin + exp) / Convert.ToDecimal(2.0)); } else
{
subMin = Math.Round((exp + boundMax) / Convert.ToDecimal(2.0));
}
decimal expBound = (boundMin + boundMax) / 2;
decimal expSub = (subMin + subMax) / 2;
decimal subRate = (exp - expBound) / (expSub - expBound);
return getRandomValWithSpecifySubRate(boundMin, boundMax, subMin, subMax, subRate);
}
/// <summary>
/// 下限随机
/// </summary>
/// <param name="rate"></param>
/// <returns></returns>
private bool canReward(decimal rate)
{
return Convert.ToDecimal(ra.NextDouble().ToString()) <= rate;
}
/**
* Return a random number in the min~max range, including min and max
* @param min
* @param max
* @return
*/
private decimal getRandomVal(decimal min, decimal max)
{ decimal v = Convert.ToDecimal(ra. NextDouble()) * max; v = Convert.ToDecimal(v.ToString("#0.00")); return v >= min? V: min; }
/// <summary>
/// Random algorithm with probability bias, the probability bias in the subMin~subMax interval returns a random number in the boundMin~boundMax interval (including boundMin and boundMax), and at the same time, you can specify the priority probability of subMin~subMax. Example: Pass in the parameters (10, 50, 20, 30, 0.8), and the random result will be returned randomly from 20 to 30 with 80% probability, and randomly returned from 10 to 50 with 20% probability
/// </summary>
// / <param name="boundMin"></param>
/// <param name="boundMax"></param>
/// <param name="subMin"></param>
/// <param name= "subMax"></param>
/// <param name="subRate"></param>
/// <returns></returns>
private decimal getRandomValWithSpecifySubRate(decimal boundMin, decimal boundMax, decimal subMin, decimal subMax,decimal subRate)
{ if (canReward(subRate)) {
return getRandomVal(subMin, subMax);
}
return getRandomVal(boundMin, boundMax);
}
}
}