Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 生成具有特定和的随机整数_C#_Algorithm - Fatal编程技术网

C# 生成具有特定和的随机整数

C# 生成具有特定和的随机整数,c#,algorithm,C#,Algorithm,我有5个字段,我希望它们都有一个0到100之间的生成数字。但是,5个字段的总和应该是100 当我想为一个字段提供一个随机数时,我会执行以下操作: Random rnd = new Random(); int x= rnd.Next(1, 10); 但是,对于需要合计100的多个字段,我应该如何做到这一点呢?创建第一个随机数。然后,取num1的值与100之间的差值作为rnd的最大def。但是为了保证它们的总和是100,您必须在最后一次检查所有num的总和是否为100。如果不是,则上一个num的值

我有5个字段,我希望它们都有一个0到100之间的生成数字。但是,5个字段的总和应该是100

当我想为一个字段提供一个随机数时,我会执行以下操作:

Random rnd = new Random();
int x= rnd.Next(1, 10);

但是,对于需要合计100的多个字段,我应该如何做到这一点呢?

创建第一个随机数。然后,取
num1
的值与100之间的差值作为rnd的
最大def
。但是为了保证它们的总和是100,您必须在最后一次检查所有
num
的总和是否为100。如果不是,则上一个
num
的值是它们的总和与100的差值

为了简化代码并获得干净的结构,将代码放入循环中,而不是使用
int[5]
数组处理单个数字


private int[]CreateRandomNumbersWithSum()
{
int[]nums=新的int[5];
内差=100;
随机rnd=新随机();
对于(int i=0;i
我认为这是一个非常简单的解决方案:

public void GenerateRandNr(int total)
    {
        var rnd = new Random();
        var nr1 = rnd.Next(0, total);
        var nr2 = rnd.Next(0, total - nr1);
        var nr3 = rnd.Next(0, total - nr1 - nr2);
        var nr4 = rnd.Next(0, total - nr1 - nr2 - nr3);
        var nr5 = total - nr1 - nr2 - nr3 - nr4;
    }
public static int[] GetRandomDistribution(int sum, int amountOfNumbers)
{

    int[] numbers = new int[amountOfNumbers];
    var random = new Random();
    for (int i = 0; i < sum; i++)
    {
      numbers[random.Next(0, amountOfNumbers)]++;
    }
    return numbers;
}

static void Main(string[] args)
{
    var result = GetRandomDistribution(100, 5);
}
编辑: 刚刚测试过,对我来说很好:

例如

int sum=100;
int i = 5;
Random rnd = new Random();
while (true)
{
    int cur;                
    --i;
    if (i == 0) {
        Console.WriteLine(sum + " ");
        break;
    } else 
        cur=rnd.Next(1, sum);
    sum -= cur;        
    Console.WriteLine(cur + " ");                
}
实例:


为了实现真正的随机分布,每个元素都有机会达到100,总的总数为100,您可以使用以下解决方案:

public void GenerateRandNr(int total)
    {
        var rnd = new Random();
        var nr1 = rnd.Next(0, total);
        var nr2 = rnd.Next(0, total - nr1);
        var nr3 = rnd.Next(0, total - nr1 - nr2);
        var nr4 = rnd.Next(0, total - nr1 - nr2 - nr3);
        var nr5 = total - nr1 - nr2 - nr3 - nr4;
    }
public static int[] GetRandomDistribution(int sum, int amountOfNumbers)
{

    int[] numbers = new int[amountOfNumbers];
    var random = new Random();
    for (int i = 0; i < sum; i++)
    {
      numbers[random.Next(0, amountOfNumbers)]++;
    }
    return numbers;
}

static void Main(string[] args)
{
    var result = GetRandomDistribution(100, 5);
}
public static int[]GetRandomDistribution(整数和,整数数量)
{
int[]数字=新的int[amountOfNumbers];
var random=新的random();
对于(int i=0;i
它将随机数增加1,直到达到总和。这应该符合你的所有标准

仔细考虑后,我更喜欢以下解决方案,因为它不太可能产生相等的分布:

public static int[] GetRandomDistribution2(int sum, int amountOfNumbers)
{

    int[] numbers = new int[amountOfNumbers];

    var random = new Random();

    for (int i = 0; i < amountOfNumbers; i++)
    {
      numbers[i] = random.Next(sum);
    }


    var compeleteSum = numbers.Sum();

    // Scale the numbers down to 0 -> sum
    for (int i = 0; i < amountOfNumbers; i++)
    {
      numbers[i] = (int)(((double)numbers[i] / compeleteSum) * sum);
    }

    // Due to rounding the number will most likely be below sum
    var resultSum = numbers.Sum();

    // Add +1 until we reach "sum"
    for (int i = 0; i < sum - resultSum; i++)
    {
      numbers[random.Next(0, amountOfNumbers)]++;
    }

    return numbers;
}
public static int[]GetRandomDistribution2(int总和,int数量)
{
int[]数字=新的int[amountOfNumbers];
var random=新的random();
对于(int i=0;isum
对于(int i=0;i
为了使您的分发更加统一,您可以尝试以下方法:

  • 生成一些随机数
  • 使它们正常化
  • 如果需要,请更正最后一个字段以获得准确的预期总和
  • 守则:

    const int ExpectedSum = 100;
    
    Random rnd = new Random();
    int[] fields = new int[5];
    
    // Generate 4 random values and get their sum
    int sum = 0;
    for (int i = 0; i < fields.Length - 1; i++)
    {
        fields[i] = rnd.Next(ExpectedSum);
        sum += fields[i];
    }
    
    // Adjust the sum as if there were 5 random values
    int actualSum = sum * fields.Length / (fields.Length - 1);
    
    // Normalize 4 random values and get their sum
    sum = 0;
    for (int i = 0; i < fields.Length - 1; i++)
    {
        fields[i] = fields[i] * ExpectedSum / actualSum;
        sum += fields[i];
    }
    
    // Set the last value
    fields[fields.Length - 1] = ExpectedSum - sum;
    
    const int ExpectedSum=100;
    随机rnd=新随机();
    int[]字段=新的int[5];
    //生成4个随机值并得到它们的和
    整数和=0;
    for(int i=0;i

    实例:

    您可以使用以下方法:

  • 在[01100]中生成4个随机整数
  • 对它们进行排序,让我们将排序后的值表示为0≤ x1≤ x2≤ x3≤ x4≤ 一百
  • 使用以下5个值作为总和为100的随机数:
    • N1=x1
    • N2=x2-x1
    • N3=x3-x2
    • N4=x4-x3
    • N5=100-x4

  • 它基本上对应于在[0,100]间隔上随机选择4个剖切点,并使用5个结果间隔的长度作为随机数:

    const int k=5;
    常数整数和=100;
    随机rnd=新随机();
    int[]x=新的int[k+1];
    //区间的端点
    x[0]=0;
    x[k]=总和;
    //生成k-1随机剖切点
    对于(int i=1;i
    解决方案是,不是数字需要随机,而是分布需要随机。这些数字的随机性将是其随机分布的副作用

    你可以从给定范围内的五个随机数开始。准确的范围并不重要,只要这五种情况下的范围都相同,尽管更宽的范围允许更多的变化。我会使用Random.NextDouble()返回0到1之间的随机数

    每个单独的数字除以这些数字的总和代表一个分布

    例如,假设您的随机数为.4、.7、.2、.5、.2。(为了简单起见,使用更少的数字。)

    这些数字的总数是2。现在分布是这些数字除以总数

    .4 / 2 = .20
    .7 / 2 = .35
    .2 / 2 = .10
    .5 / 2 = .25
    .2 / 2 = .10
    
    您会注意到,如果小数位数更多,这些分布将等于100%或非常接近

    输出将是这些分布中的每一个乘以目标数,在本例中为100。换言之,这些数字中的每一个都代表了一块100

    将这些分布乘以目标,我们得到20,35,10,25,
    .4 / 2 = .20
    .7 / 2 = .35
    .2 / 2 = .10
    .5 / 2 = .25
    .2 / 2 = .10
    
    public class RandomlyDistributesNumbersTotallingTarget
    {
        public IEnumerable<int> GetTheNumbers(int howManyNumbers, int targetTotal)
        {
            var random = new Random();
            var distributions = new List<double>();
            for (var addDistributions = 0; addDistributions < howManyNumbers; addDistributions++)
            {
                distributions.Add(random.NextDouble());
            }
            var sumOfDistributions = distributions.Sum();
            var output = distributions.Select(
                distribution => 
                    (int)Math.Round(distribution / sumOfDistributions * targetTotal, 0)).ToList();
            RoundUpOutput(output, targetTotal);
            return output;
        }
    
        private void RoundUpOutput(List<int> output, int targetTotal)
        {
            var difference = targetTotal - output.Sum();
            if (difference !=0)
            {
                var indexToAdjust =
                    difference > 0 ? output.IndexOf(output.Min()) : output.IndexOf(output.Max());
                output[indexToAdjust]+= difference;
            }
        }
    }
    
    [TestMethod]
    public void OutputTotalsTarget()
    {
        var subject = new RandomlyDistributesNumbersTotallingTarget();
        for (var x = 0; x < 10000; x++)
        {
            var output = subject.GetTheNumbers(5, 100);
            Assert.AreEqual(100, output.Sum());
        }
    }
    
    var rnd = new Random();
    var numbers = Enumerable.Range(0, 5).Select(x => rnd.Next(0, 101)).ToArray().OrderBy(x => x).ToArray();
    numbers = numbers.Zip(numbers.Skip(1), (n0, n1) => n1 - n0).ToArray();
    numbers = numbers.Concat(new[] { 100 - numbers.Sum() }).ToArray();
    
    public static int[] UniformNormalization(this Random r, int valueCount, int valueSum)
    {
        var ret = new int[valueCount];
        long sum = 0;
        for (int i = 0; i < valueCount; i++)
        {
            var next = r.Next(0, valueSum);
            ret[i] = next;
            sum += next;
        }
    
        var actualSum = 0;
    
        for (int i = 0; i < valueCount; i++)
        {
            actualSum += ret[i] = (int)((ret[i] * valueSum) / sum);
        }
    
        //Fix integer rounding errors.
        if (valueSum > actualSum)
        {
            for (int i = 0; i < valueSum - actualSum; i++)
            {
                ret[r.Next(0, valueCount)]++;
            }
        }
    
        return ret;
    }